예제 #1
0
        public override bool IsEqualTo(TableExpression expression)
        {
            SubSelectExpression subSelectTable = expression as SubSelectExpression;

            if (subSelectTable == null)
            {
                return(false);
            }
            return(Name == expression.Name && JoinID == expression.JoinID && Select == subSelectTable.Select);
        }
        protected virtual Expression AnalyzeProjectionQuery(SqlFunctionType specialExpressionType, IList<Expression> parameters,
            TranslationContext context, bool canHaveFilter = true)
        {
            if (context.IsExternalInExpressionChain)
            {
                var operand0 = Analyze(parameters[0], context);
                Expression functionOperand = null;
                Expression projectionOperand;

                if (    context.CurrentSelect.NextSelectExpression != null
                    ||  context.CurrentSelect.Operands.Count() > 0
                    ||  context.CurrentSelect.Group.Count > 0
                   )
                {
                    // No TableInfo in projection
                    operand0 = new SubSelectExpression(context.CurrentSelect, operand0.Type, "source", null);
                    context.NewParentSelect();

                    // In the new scope we should not have MaximumDatabaseLoad
                    //context.QueryContext.MaximumDatabaseLoad = false;

                    context.CurrentSelect.Tables.Add(operand0 as TableExpression);
                }

                // basically, we have three options for projection methods:
                // - projection on grouped table (1 operand, a GroupExpression)
                // - projection on grouped column (2 operands, GroupExpression and ColumnExpression)
                // - projection on table/column, with optional restriction
                var groupOperand0 = operand0 as GroupExpression;
                if (groupOperand0 != null)
                {
                    if (parameters.Count > 1)
                        projectionOperand = Analyze(parameters[1], groupOperand0.GroupedExpression, context);
                    else
                        projectionOperand = Analyze(groupOperand0.GroupedExpression, context);
                }
                else
                {
                    projectionOperand = operand0;
                    if (parameters.Count > 1)
                      functionOperand = Analyze(parameters[1], operand0, context);
                    int filterIndex = canHaveFilter ? 1 : -1; //special case for Average - its second parameter is NOT filter
                    CheckWhere(projectionOperand, parameters, filterIndex, context);
                }

                if (projectionOperand is TableExpression)
                    projectionOperand = RegisterTable((TableExpression)projectionOperand, context);

                if (groupOperand0 != null) {
                  var childColumns = GetChildColumns(projectionOperand, context);
                  projectionOperand = new GroupExpression(projectionOperand, groupOperand0.KeyExpression, childColumns);
                }

                var opList = new List<Expression>();
                opList.Add(projectionOperand);
                if (functionOperand != null)
                  opList.Add(functionOperand);
                return CreateSqlFunction(specialExpressionType, opList.ToArray());
            }
            else
            {
                var subQueryContext = context.NewSelect();

                var tableExpression = Analyze(parameters[0], subQueryContext);

                //RI: new stuff - handling grouping with aggregates
                //if (IsAggregate(specialExpressionType)) {
                  var grpExpr = tableExpression as GroupExpression;
                  var srcTable = grpExpr == null ? tableExpression : grpExpr.GroupedExpression ;
                  SqlFunctionExpression specialExpr;
                  if (parameters.Count > 1) {
                    var predicate = Analyze(parameters[1], srcTable, subQueryContext);
                    specialExpr = CreateSqlFunction(specialExpressionType, tableExpression, predicate);
                  } else {
                    specialExpr = CreateSqlFunction(specialExpressionType, tableExpression);
                  }
                  // If subQuery context has no tables added, it is not a subquery, it's just an aggregate function over 'main' table
                  var currSelect = subQueryContext.CurrentSelect;
                  if (currSelect.Tables.Count == 0)
                    return specialExpr;
                  //this is a real subquery, so mutate and return the current select from this context
                  currSelect = currSelect.ChangeOperands(new Expression[] { specialExpr }, currSelect.Operands);
                  return currSelect;
                //}
                //RI: end my special code
            }
        }
        /// <summary>
        /// Any() returns true if the given condition satisfies at least one of provided elements
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        protected virtual Expression AnalyzeAny(IList<Expression> parameters, TranslationContext context)
        {
            if (context.IsExternalInExpressionChain)
            {
                var tableExpression = Analyze(parameters[0], context);
                Expression projectionOperand;

                if (context.CurrentSelect.NextSelectExpression != null)
                {
                    TableExpression currentTableExpression = tableExpression as TableExpression;
                    tableExpression = new SubSelectExpression(context.CurrentSelect, currentTableExpression.Type, "source", currentTableExpression.TableInfo);
                    context.NewParentSelect();

                    // In the new scope we should not have MaximumDatabaseLoad
                    //context.QueryContext.MaximumDatabaseLoad = false;

                    context.CurrentSelect.Tables.Add(tableExpression as TableExpression);
                }

                // basically, we have three options for projection methods:
                // - projection on grouped table (1 operand, a GroupExpression)
                // - projection on grouped column (2 operands, GroupExpression and ColumnExpression)
                // - projection on table/column, with optional restriction
                var groupOperand0 = tableExpression as GroupExpression;
                if (groupOperand0 != null)
                {
                    if (parameters.Count > 1)
                    {
                        projectionOperand = Analyze(parameters[1], groupOperand0.GroupedExpression,
                                                    context);
                    }
                    else
                        projectionOperand = Analyze(groupOperand0.GroupedExpression, context);
                }
                else
                {
                    projectionOperand = tableExpression;
                    CheckWhere(projectionOperand, parameters, 1, context);
                }

                if (projectionOperand is TableExpression)
                    projectionOperand = RegisterTable((TableExpression)projectionOperand, context);

                if (groupOperand0 != null) {
                  var childColumns = GetChildColumns(groupOperand0.KeyExpression, context);
                  projectionOperand = new GroupExpression(projectionOperand, groupOperand0.KeyExpression, childColumns);
                }

                return ExpressionUtil.MakeGreaterThanZero(CreateSqlFunction(SqlFunctionType.Count, projectionOperand));
            }
            else
            {
                var anyBuilderContext = context.NewSelect();
                var tableExpression = Analyze(parameters[0], anyBuilderContext);

                if (!(tableExpression is TableExpression))
                    tableExpression = Analyze(tableExpression, anyBuilderContext);

                // from here we build a custom clause:
                // <anyClause> ==> "(select count(*) from <table> where <anyClause>)>0"
                // TODO (later...): see if some vendors support native Any operator and avoid this substitution
                if (parameters.Count > 1)
                {
                    var anyClause = Analyze(parameters[1], tableExpression, anyBuilderContext);
                    RegisterWhere(anyClause, anyBuilderContext);
                }
                var countExpr = CreateSqlFunction(SqlFunctionType.Count, tableExpression);
                var currSelect = anyBuilderContext.CurrentSelect;
                anyBuilderContext.CurrentSelect = currSelect.ChangeOperands(new Expression[] {countExpr}, currSelect.Operands);
                // TODO: see if we need to register the tablePiece here (we probably don't)

                // we now switch back to current context, and compare the result with 0
                // note - we might have count returning int or long, so we must adjust 0 constant (int or long)
                var anyExpression = ExpressionUtil.MakeGreaterThanZero(anyBuilderContext.CurrentSelect);
                return anyExpression;
            }
        }
        /// <summary>
        /// "Distinct" means select X group by X
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        protected virtual Expression AnalyzeDistinct(IList<Expression> parameters, TranslationContext context)
        {
            var expression = Analyze(parameters[0], context);
            // we select and group by the same criterion
            // RI: adding explicit list of columns, to catch situation of duplicate column names in joins
            var childColumns = GetChildColumns(expression, context);
            // some providers (ex SQL CE) do not allow Text columns in distinct output
            CheckDistinctClauseColumns(childColumns, context);

            var group = new GroupExpression(expression, expression, childColumns);
            if (context.CurrentSelect.NextSelectExpression != null)
            {
                var tableInfo = context.DbModel.GetTable(expression.Type);
                expression = new SubSelectExpression(context.CurrentSelect, expression.Type, "source", tableInfo);
                context.NewParentSelect();

                // In the new scope we should not have MaximumDatabaseLoad
                //context.QueryContext.MaximumDatabaseLoad = false;

                context.CurrentSelect.Tables.Add(expression as TableExpression);
            }
            context.CurrentSelect.Group.Add(group);

            //RI: added this special check
            // var table
            // var cols = RegisterAllColumns()

            // "Distinct" method is equivalent to a GroupBy
            // but for some obscure reasons, Linq expects a IQueryable instead of an IGrouping
            // so we return the column, not the group
            return expression;
        }
        protected virtual Expression AnalyzeSelectOperation(SelectOperatorType operatorType, IList<Expression> parameters, TranslationContext context)
        {
            // a special case: if we have several SELECT expressions linked together,
            // we maximize the load to the database, since the result must use the same parameters
            // types and count.
            //context.QueryContext.MaximumDatabaseLoad = true; // all select expression goes to SQL tier
            var subQuery = parameters[1];
            if (subQuery != null) {
              // Handle second select first
              TranslationContext newContext = context.NewSisterSelect();
              Expression tableExpression = AnalyzeSubQuery(subQuery, newContext);
              BuildSelect(tableExpression, newContext);

              // add the second select select to the chain
              if (newContext.CurrentSelect.NextSelectExpression != null) {
                var typedTable = tableExpression as TableExpression;
                var dbTable = typedTable == null ? null : typedTable.TableInfo;
                var operand0 = new SubSelectExpression(newContext.CurrentSelect, tableExpression.Type, "source", dbTable);
                newContext.NewParentSelect();
                newContext.CurrentSelect.Tables.Add(operand0);
              }
              SelectExpression selectToModify = context.CurrentSelect;
              while (selectToModify.NextSelectExpression != null)
                selectToModify = selectToModify.NextSelectExpression;

              selectToModify.NextSelectExpression = newContext.CurrentSelect;
              selectToModify.NextSelectExpressionOperator = operatorType;

              Expression firstSelection = Analyze(parameters[0], context);
              BuildSelect(firstSelection, context);

              return firstSelection;
            }
            return Analyze(parameters[0], context);
        }