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); }