public override IQuerySqlGenerator CreateDefault(SelectExpression selectExpression)
     => new MyCatQuerySqlGenerator(
         CommandBuilderFactory,
         SqlGenerationHelper,
         ParameterNameGeneratorFactory,
         RelationalTypeMapper,
         Check.NotNull(selectExpression, nameof(selectExpression)));
Example #2
0
        private void DiscriminateProjectionQuery(
            IEntityType entityType, Microsoft.EntityFrameworkCore.Query.Expressions.SelectExpression selectExpression, IQuerySource querySource)
        {
            Expression discriminatorPredicate;

            if (entityType.IsQueryType)
            {
                discriminatorPredicate = GenerateDiscriminatorExpression(entityType, selectExpression, querySource);
            }
            else
            {
                var sharedTypes = new HashSet <IEntityType>(
                    _model.GetEntityTypes()
                    .Where(e => !e.IsQueryType)
                    .Where(
                        et => et.Relational().TableName == entityType.Relational().TableName &&
                        et.Relational().Schema == entityType.Relational().Schema));

                var currentPath = new Stack <IEntityType>();
                currentPath.Push(entityType);

                var allPaths = new List <List <IEntityType> >();
                FindPaths(entityType.RootType(), sharedTypes, currentPath, allPaths);

                discriminatorPredicate = allPaths
                                         .Select(
                    p => p.Select(
                        et => GenerateDiscriminatorExpression(et, selectExpression, querySource))
                    .Aggregate(
                        (Expression)null,
                        (result, current) => result != null
                                    ? current != null
                                        ? Expression.AndAlso(result, current)
                                        : result
                                    : current))
                                         .Aggregate(
                    (Expression)null,
                    (result, current) => result != null
                            ? current != null
                                ? Expression.OrElse(result, current)
                                : result
                            : current);
            }

            if (discriminatorPredicate != null)
            {
                selectExpression.Predicate = new DiscriminatorPredicateExpression(discriminatorPredicate, querySource);
            }
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        protected override void GenerateLimitOffset(SelectExpression selectExpression)
        {
            if (selectExpression.Projection.OfType<RowNumberExpression>().Any())
            {
                return;
            }

            if (selectExpression.Offset != null
                && !selectExpression.OrderBy.Any())
            {
                Sql.AppendLine().Append("ORDER BY @@ROWCOUNT");
            }

            base.GenerateLimitOffset(selectExpression);
        }
 public virtual SqlTranslatingExpressionVisitor Create(
     RelationalQueryModelVisitor queryModelVisitor,
     SelectExpression targetSelectExpression = null,
     Expression topLevelPredicate = null,
     bool bindParentQueries = false,
     bool inProjection = false)
     => new SqlTranslatingExpressionVisitor(
         _relationalAnnotationProvider,
         _compositeExpressionFragmentTranslator,
         _methodCallTranslator,
         _memberTranslator,
         Check.NotNull(queryModelVisitor, nameof(queryModelVisitor)),
         targetSelectExpression,
         topLevelPredicate,
         bindParentQueries,
         inProjection);
Example #5
0
        private Shaper CreateShaper(Type elementType, IEntityType entityType, Microsoft.EntityFrameworkCore.Query.Expressions.SelectExpression selectExpression)
        {
            Shaper shaper;

            if (QueryModelVisitor.QueryCompilationContext
                .QuerySourceRequiresMaterialization(_querySource) ||
                QueryModelVisitor.RequiresClientEval)
            {
                var materializerExpression
                    = _materializerFactory
                      .CreateMaterializer(
                          entityType,
                          selectExpression,
                          (p, se) =>
                          se.AddToProjection(
                              p,
                              _querySource),
                          out var typeIndexMap);

                var materializer = materializerExpression.Compile();

                shaper
                    = (Shaper)_createEntityShaperMethodInfo.MakeGenericMethod(elementType)
                      .Invoke(
                          obj: null,
                          parameters: new object[]
                {
                    _querySource,
                    QueryModelVisitor.QueryCompilationContext.IsTrackingQuery &&
                    !entityType.IsQueryType,
                    entityType.FindPrimaryKey(),
                    materializer,
                    materializerExpression,
                    typeIndexMap,
                    QueryModelVisitor.QueryCompilationContext.IsQueryBufferRequired &&
                    !entityType.IsQueryType
                });
            }
            else
            {
                shaper = new ValueBufferShaper(_querySource);
            }

            return(shaper);
        }
Example #6
0
        private static Expression GenerateDiscriminatorExpression(
            IEntityType entityType, Microsoft.EntityFrameworkCore.Query.Expressions.SelectExpression selectExpression, IQuerySource querySource)
        {
            var concreteEntityTypes
                = entityType.GetConcreteTypesInHierarchy().ToList();

            if (concreteEntityTypes.Count == 1 &&
                concreteEntityTypes[0].RootType() == concreteEntityTypes[0])
            {
                return(null);
            }

            var discriminatorColumn
                = selectExpression.BindProperty(
                      concreteEntityTypes[0].Relational().DiscriminatorProperty,
                      querySource);

            var firstDiscriminatorValue
                = Expression.Constant(
                      concreteEntityTypes[0].Relational().DiscriminatorValue,
                      discriminatorColumn.Type);

            var discriminatorPredicate
                = Expression.Equal(discriminatorColumn, firstDiscriminatorValue);

            if (concreteEntityTypes.Count > 1)
            {
                discriminatorPredicate
                    = concreteEntityTypes
                      .Skip(1)
                      .Select(
                          concreteEntityType
                          => Expression.Constant(
                              concreteEntityType.Relational().DiscriminatorValue,
                              discriminatorColumn.Type))
                      .Aggregate(
                          discriminatorPredicate, (current, discriminatorValue) =>
                          Expression.OrElse(
                              Expression.Equal(discriminatorColumn, discriminatorValue),
                              current));
            }

            return(discriminatorPredicate);
        }
        protected override void GenerateLimitOffset(SelectExpression selectExpression)
        {
            Check.NotNull(selectExpression, nameof(selectExpression));

            if ((selectExpression.Limit != null)
                || (selectExpression.Offset != null))
            {
                Sql.AppendLine()
                    .Append("LIMIT ");

                Visit(selectExpression.Limit ?? Expression.Constant(-1));

                if (selectExpression.Offset != null)
                {
                    Sql.Append(" OFFSET ");

                    Visit(selectExpression.Offset);
                }
            }
        }
        public virtual SelectExpression Clone([NotNull] string alias)
        {
            Check.NotNull(alias, nameof(alias));

            var selectExpression
                = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext, alias)
                {
                    _limit = _limit,
                    _offset = _offset,
                    _isDistinct = _isDistinct,
                    _subqueryDepth = _subqueryDepth,
                    IsProjectStar = IsProjectStar,
                    Predicate = Predicate
                };

            selectExpression._projection.AddRange(_projection);

            selectExpression.AddTables(_tables);
            selectExpression.AddToOrderBy(_orderBy);

            return selectExpression;
        }
Example #9
0
        /// <summary>
        ///     Creates a new instance of a ExistsExpression..
        /// </summary>
        /// <param name="subquery"> The subquery operand of the EXISTS expression. </param>
        public ExistsExpression([NotNull] SelectExpression subquery)
        {
            Check.NotNull(subquery, nameof(subquery));

            Subquery = subquery;
        }
            private Expression VisitSelectExpression(SelectExpression selectExpression)
            {
                base.Visit(selectExpression);

                if (!RequiresRowNumberPaging(selectExpression))
                {
                    return selectExpression;
                }

                var subQuery = selectExpression.PushDownSubquery();

                foreach (var projection in subQuery.Projection)
                {
                    var alias = projection as AliasExpression;
                    var column = projection as ColumnExpression;

                    if (column != null)
                    {
                        column = new ColumnExpression(column.Name, column.Property, subQuery);
                        selectExpression.AddToProjection(column);
                        continue;
                    }

                    column = alias?.TryGetColumnExpression();

                    if (column != null)
                    {
                        column = new ColumnExpression(alias.Alias ?? column.Name, column.Property, subQuery);
                        alias = new AliasExpression(alias.Alias, column);
                        selectExpression.AddToProjection(alias);
                    }
                    else
                    {
                        column = new ColumnExpression(alias?.Alias, alias.Expression.Type, subQuery);
                        selectExpression.AddToProjection(column);
                    }
                }

                if (subQuery.OrderBy.Count == 0)
                {
                    subQuery.AddToOrderBy(
                        new Ordering(new SqlFunctionExpression("@@RowCount", typeof(int)), OrderingDirection.Asc));
                }

                var columnExpression = new ColumnExpression(RowNumberColumnName, typeof(int), subQuery);
                var rowNumber = new RowNumberExpression(columnExpression, subQuery.OrderBy);

                subQuery.ClearOrderBy();
                subQuery.AddToProjection(rowNumber, false);

                Expression predicate = null;

                var offset = subQuery.Offset ?? Expression.Constant(0);

                if (subQuery.Offset != null)
                {
                    predicate = Expression.GreaterThan(columnExpression, offset);
                }

                if (subQuery.Limit != null)
                {
                    var constantValue = (subQuery.Limit as ConstantExpression)?.Value;
                    var offsetValue = (offset as ConstantExpression)?.Value;

                    var limitExpression
                        = constantValue != null
                          && offsetValue != null
                            ? (Expression)Expression.Constant((int)offsetValue + (int)constantValue)
                            : Expression.Add(offset, subQuery.Limit);

                    var expression = Expression.LessThanOrEqual(columnExpression, limitExpression);

                    if (predicate != null)
                    {
                        expression = Expression.AndAlso(predicate, expression);
                    }

                    predicate = expression;
                }

                selectExpression.Predicate = predicate;

                return selectExpression;
            }
 private static bool RequiresRowNumberPaging(SelectExpression selectExpression)
     => selectExpression.Offset != null
        && !selectExpression.Projection.Any(p => p is RowNumberExpression);
 /// <summary>
 ///     Creates a query SQL generator for a FromSql query.
 /// </summary>
 /// <param name="selectExpression"> The select expression. </param>
 /// <param name="sql"> The SQL. </param>
 /// <param name="arguments"> The arguments. </param>
 /// <returns>
 ///     The query SQL generator.
 /// </returns>
 public virtual IQuerySqlGenerator CreateFromSql(
     SelectExpression selectExpression,
     string sql,
     Expression arguments)
     => new FromSqlNonComposedQuerySqlGenerator(
         CommandBuilderFactory,
         SqlGenerationHelper,
         ParameterNameGeneratorFactory,
         RelationalTypeMapper,
         Check.NotNull(selectExpression, nameof(selectExpression)),
         Check.NotEmpty(sql, nameof(sql)),
         Check.NotNull(arguments, nameof(arguments)));
        /// <summary>
        ///     Makes a copy of this SelectExpression.
        /// </summary>
        /// <param name="alias"> The alias. </param>
        /// <returns>
        ///     A copy of this SelectExpression.
        /// </returns>
        public virtual SelectExpression Clone([CanBeNull] string alias = null)
        {
            var selectExpression
                = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext)
                {
                    _limit = _limit,
                    _offset = _offset,
                    _isDistinct = _isDistinct,
                    _subqueryDepth = _subqueryDepth,
                    IsProjectStar = IsProjectStar,
                    Predicate = Predicate
                };

            if (alias != null)
            {
                selectExpression.Alias = _queryCompilationContext.CreateUniqueTableAlias(alias);
            }

            selectExpression._projection.AddRange(_projection);

            selectExpression.AddTables(_tables);
            selectExpression.AddToOrderBy(_orderBy);

            return selectExpression;
        }
 public override IQuerySqlGenerator CreateDefault(SelectExpression selectExpression)
 {
     throw new NotImplementedException();
 }
 /// <summary>
 ///     Creates a default query SQL generator.
 /// </summary>
 /// <param name="selectExpression"> The select expression. </param>
 /// <returns>
 ///     The new default query SQL generator.
 /// </returns>
 public abstract IQuerySqlGenerator CreateDefault(SelectExpression selectExpression);
 protected override void GenerateTop(SelectExpression selectExpression)
 {
     // Handled by GenerateLimitOffset
 }
        public virtual Expression<Func<ValueBuffer, object>> CreateMaterializer(
            IEntityType entityType,
            SelectExpression selectExpression,
            Func<IProperty, SelectExpression, int> projectionAdder,
            IQuerySource querySource)
        {
            Check.NotNull(entityType, nameof(entityType));
            Check.NotNull(selectExpression, nameof(selectExpression));
            Check.NotNull(projectionAdder, nameof(projectionAdder));

            var valueBufferParameter
                = Expression.Parameter(typeof(ValueBuffer), "valueBuffer");

            var concreteEntityTypes
                = entityType.GetConcreteTypesInHierarchy().ToArray();

            var indexMap = new int[concreteEntityTypes[0].PropertyCount()];
            var propertyIndex = 0;

            foreach (var property in concreteEntityTypes[0].GetProperties())
            {
                indexMap[propertyIndex++]
                    = projectionAdder(property, selectExpression);
            }

            var materializer
                = _entityMaterializerSource
                    .CreateMaterializeExpression(
                        concreteEntityTypes[0], valueBufferParameter, indexMap);

            if (concreteEntityTypes.Length == 1
                && concreteEntityTypes[0].RootType() == concreteEntityTypes[0])
            {
                return Expression.Lambda<Func<ValueBuffer, object>>(materializer, valueBufferParameter);
            }

            var discriminatorProperty = _relationalAnnotationProvider.For(concreteEntityTypes[0]).DiscriminatorProperty;

            var discriminatorColumn
                = selectExpression.Projection
                    .OfType<AliasExpression>()
                    .Last(c => c.TryGetColumnExpression()?.Property == discriminatorProperty);

            var firstDiscriminatorValue
                = Expression.Constant(
                    _relationalAnnotationProvider.For(concreteEntityTypes[0]).DiscriminatorValue);

            var discriminatorPredicate
                = Expression.Equal(discriminatorColumn, firstDiscriminatorValue);

            if (concreteEntityTypes.Length == 1)
            {
                selectExpression.Predicate
                    = new DiscriminatorPredicateExpression(discriminatorPredicate, querySource);

                return Expression.Lambda<Func<ValueBuffer, object>>(materializer, valueBufferParameter);
            }

            var discriminatorValueVariable
                = Expression.Variable(discriminatorProperty.ClrType);

            var returnLabelTarget = Expression.Label(typeof(object));

            var blockExpressions
                = new Expression[]
                {
                    Expression.Assign(
                        discriminatorValueVariable,
                        _entityMaterializerSource
                            .CreateReadValueExpression(
                                valueBufferParameter,
                                discriminatorProperty.ClrType,
                                discriminatorProperty.GetIndex())),
                    Expression.IfThenElse(
                        Expression.Equal(discriminatorValueVariable, firstDiscriminatorValue),
                        Expression.Return(returnLabelTarget, materializer),
                        Expression.Throw(
                            Expression.Call(
                                _createUnableToDiscriminateException,
                                Expression.Constant(concreteEntityTypes[0])))),
                    Expression.Label(
                        returnLabelTarget,
                        Expression.Default(returnLabelTarget.Type))
                };

            foreach (var concreteEntityType in concreteEntityTypes.Skip(1))
            {
                indexMap = new int[concreteEntityType.PropertyCount()];
                propertyIndex = 0;

                foreach (var property in concreteEntityType.GetProperties())
                {
                    indexMap[propertyIndex++]
                        = projectionAdder(property, selectExpression);
                }

                var discriminatorValue
                    = Expression.Constant(
                        _relationalAnnotationProvider.For(concreteEntityType).DiscriminatorValue);

                materializer
                    = _entityMaterializerSource
                        .CreateMaterializeExpression(concreteEntityType, valueBufferParameter, indexMap);

                blockExpressions[1]
                    = Expression.IfThenElse(
                        Expression.Equal(discriminatorValueVariable, discriminatorValue),
                        Expression.Return(returnLabelTarget, materializer),
                        blockExpressions[1]);

                discriminatorPredicate
                    = Expression.OrElse(
                        Expression.Equal(discriminatorColumn, discriminatorValue),
                        discriminatorPredicate);
            }

            selectExpression.Predicate
                = new DiscriminatorPredicateExpression(discriminatorPredicate, querySource);

            return Expression.Lambda<Func<ValueBuffer, object>>(
                Expression.Block(new[] { discriminatorValueVariable }, blockExpressions),
                valueBufferParameter);
        }
        /// <summary>
        ///     Creates a subquery based on this SelectExpression and makes that table the single entry in
        ///     <see cref="Tables" />. Clears all other top-level aspects of this SelectExpression.
        /// </summary>
        /// <returns>
        ///     A SelectExpression.
        /// </returns>
        public virtual SelectExpression PushDownSubquery()
        {
            _subqueryDepth++;

            var subquery = new SelectExpression(Dependencies, _queryCompilationContext, SystemAliasPrefix);

            var columnAliasCounter = 0;

            foreach (var expression in _projection)
            {
                var aliasExpression = expression as AliasExpression;

                if (aliasExpression != null)
                {
                    var columnExpression = aliasExpression.TryGetColumnExpression();

                    if ((columnExpression != null &&
                         subquery._projection.OfType <AliasExpression>()
                         .Any(ae => (ae.Alias ?? ae.TryGetColumnExpression()?.Name) == (aliasExpression.Alias ?? columnExpression.Name))) ||
                        columnExpression == null)
                    {
                        aliasExpression.Alias = "c" + columnAliasCounter++;
                    }
                }
                else
                {
                    aliasExpression = new AliasExpression("c" + columnAliasCounter++, expression);
                }

                subquery._projection.Add(aliasExpression);
            }

            subquery.AddTables(_tables);
            subquery.AddToOrderBy(_orderBy);

            subquery.Predicate = Predicate;

            subquery._limit           = _limit;
            subquery._offset          = _offset;
            subquery._isDistinct      = _isDistinct;
            subquery._subqueryDepth   = _subqueryDepth;
            subquery.ProjectStarTable = ProjectStarTable;
            subquery.IsProjectStar    = IsProjectStar || !subquery._projection.Any();

            _limit           = null;
            _offset          = null;
            _isDistinct      = false;
            ProjectStarTable = null;

            Predicate = null;

            ClearTables();
            ClearProjection();
            ClearOrderBy();

            _tables.Add(subquery);
            ProjectStarTable = subquery;

            foreach (var ordering in subquery.OrderBy)
            {
                var expression = ordering.Expression;

                var aliasExpression = expression as AliasExpression;
                if (aliasExpression != null)
                {
                    if (aliasExpression.Alias != null)
                    {
                        _orderBy.Add(
                            new Ordering(
                                new ColumnExpression(aliasExpression.Alias, aliasExpression.Type, subquery),
                                ordering.OrderingDirection));
                    }
                    else
                    {
                        var newExpression = UpdateColumnExpression(aliasExpression.Expression, subquery);

                        _orderBy.Add(
                            new Ordering(
                                new AliasExpression(newExpression), ordering.OrderingDirection));
                    }
                }
                else
                {
                    if (!subquery.IsProjectStar)
                    {
                        subquery.AddToProjection(expression);
                    }

                    var newExpression = UpdateColumnExpression(expression, subquery);

                    _orderBy.Add(
                        new Ordering(
                            new AliasExpression(newExpression), ordering.OrderingDirection));
                }
            }

            if (subquery.Limit == null &&
                subquery.Offset == null)
            {
                subquery.ClearOrderBy();
            }

            return(subquery);
        }
        public virtual SelectExpression PushDownSubquery()
        {
            _subqueryDepth++;

            var subquery = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext, SystemAliasPrefix);

            var columnAliasCounter = 0;

            foreach (var expression in _projection)
            {
                var aliasExpression = expression as AliasExpression;

                if (aliasExpression != null)
                {
                    var columnExpression = aliasExpression.TryGetColumnExpression();

                    if (columnExpression != null
                        && subquery._projection.OfType<AliasExpression>()
                            .Any(ae => ae.TryGetColumnExpression()?.Name == columnExpression.Name))
                    {
                        aliasExpression.Alias = "c" + columnAliasCounter++;
                    }
                }
                else
                {
                    aliasExpression = new AliasExpression("c" + columnAliasCounter++, expression);
                }

                subquery._projection.Add(aliasExpression);
            }

            subquery.AddTables(_tables);
            subquery.AddToOrderBy(_orderBy);

            subquery.Predicate = Predicate;

            subquery._limit = _limit;
            subquery._offset = _offset;
            subquery._isDistinct = _isDistinct;
            subquery._subqueryDepth = _subqueryDepth;
            subquery.IsProjectStar = IsProjectStar || !subquery._projection.Any();

            _limit = null;
            _offset = null;
            _isDistinct = false;

            Predicate = null;

            ClearTables();
            ClearProjection();
            ClearOrderBy();

            AddTable(subquery, createUniqueAlias: false);

            return subquery;
        }
            public bool IsCorrelated(SelectExpression selectExpression)
            {
                _selectExpression = selectExpression;

                Visit(_selectExpression);

                return _correlated;
            }