//protected virtual IQueryPlanNode VisitEquiJoin(EquiJoinNode node) { // var left = node.Left; // var right = node.Right; // if (left != null) // left = VisitNode(left); // if (right != null) // right = VisitNode(right); // return new EquiJoinNode(left, right, node.LeftColumns, node.RightColumns); //} protected virtual IQueryPlanNode VisitComposite(CompositeNode node) { var left = node.Left; var right = node.Right; if (left != null) left = VisitNode(left); if (right != null) right = VisitNode(right); return new CompositeNode(left, right, node.CompositeFunction, node.All); }
protected virtual IQueryPlanNode VisitComposite(CompositeNode node) { var left = node.Left; var right = node.Right; if (left != null) { left = VisitNode(left); } if (right != null) { right = VisitNode(right); } return(new CompositeNode(left, right, node.CompositeFunction, node.All)); }
private IQueryPlanNode PlanQuery(IQueryContext context, SqlQueryExpression queryExpression, QueryExpressionFrom queryFrom, IList<SortColumn> sortColumns) { // ----- Resolve the SELECT list // If there are 0 columns selected, then we assume the result should // show all of the columns in the result. bool doSubsetColumn = (queryExpression.SelectColumns.Any()); // What we are selecting var columns = BuildSelectColumns(queryExpression, queryFrom); // Prepare the column_set, var preparedColumns = columns.Prepare(context); sortColumns = ResolveOrderByRefs(preparedColumns, sortColumns); // ----- // Set up plans for each table in the from clause of the command. For // sub-queries, we recurse. var tablePlanner = CreateTablePlanner(context, queryFrom); // ----- // The WHERE and HAVING clauses var whereClause = queryExpression.WhereExpression; var havingClause = queryExpression.HavingExpression; PrepareJoins(tablePlanner, queryExpression, queryFrom, ref whereClause); // Prepare the WHERE and HAVING clause, qualifies all variables and // prepares sub-queries. whereClause = PrepareSearchExpression(context, queryFrom, whereClause); havingClause = PrepareSearchExpression(context, queryFrom, havingClause); // Any extra Aggregate functions that are part of the HAVING clause that // we need to add. This is a list of a name followed by the expression // that contains the aggregate function. var extraAggregateFunctions = new List<SqlExpression>(); if (havingClause != null) havingClause = FilterHaving(havingClause, extraAggregateFunctions, context); // Any GROUP BY functions, ObjectName[] groupByList; IList<SqlExpression> groupByFunctions; var gsz = ResolveGroupBy(queryExpression, queryFrom, context, out groupByList, out groupByFunctions); // Resolve GROUP MAX variable to a reference in this from set var groupmaxColumn = ResolveGroupMax(queryExpression, queryFrom); // ----- // Now all the variables should be resolved and correlated variables set // up as appropriate. // If nothing in the FROM clause then simply evaluate the result of the // select if (queryFrom.SourceCount == 0) return EvaluateToSingle(preparedColumns); // Plan the where clause. The returned node is the plan to evaluate the // WHERE clause. var node = tablePlanner.PlanSearchExpression(whereClause); SqlExpression[] defFunList; string[] defFunNames; var fsz = MakeupFunctions(preparedColumns, extraAggregateFunctions, out defFunList, out defFunNames); var groupInfo = new GroupInfo { Columns = preparedColumns, FunctionCount = fsz, FunctionNames = defFunNames, FunctionExpressions = defFunList, GroupByCount = gsz, GroupByNames = groupByList, GroupByExpressions = groupByFunctions.ToArray(), GroupMax = groupmaxColumn }; node = PlanGroup(node, groupInfo); // The result column list var selectColumns = preparedColumns.SelectedColumns.ToList(); int sz = selectColumns.Count; // Evaluate the having clause if necessary if (havingClause != null) { // Before we evaluate the having expression we must substitute all the // aliased variables. var havingExpr = havingClause; // TODO: this requires a visitor to modify the having expression havingExpr = ReplaceAliasedVariables(havingExpr, selectColumns); var source = tablePlanner.SinglePlan; source.UpdatePlan(node); node = tablePlanner.PlanSearchExpression(havingExpr); } // Do we have a composite select expression to process? IQueryPlanNode rightComposite = null; if (queryExpression.NextComposite != null) { var compositeExpr = queryExpression.NextComposite; var compositeFrom = QueryExpressionFrom.Create(context, compositeExpr); // Form the right plan rightComposite = PlanQuery(context, compositeExpr, compositeFrom, null); } // Do we do a final subset column? ObjectName[] aliases = null; if (doSubsetColumn) { // Make up the lists var subsetVars = new ObjectName[sz]; aliases = new ObjectName[sz]; for (int i = 0; i < sz; ++i) { SelectColumn scol = selectColumns[i]; subsetVars[i] = scol.InternalName; aliases[i] = scol.ResolvedName; } // If we are distinct then add the DistinctNode here if (queryExpression.Distinct) node = new DistinctNode(node, subsetVars); // Process the ORDER BY? // Note that the ORDER BY has to occur before the subset call, but // after the distinct because distinct can affect the ordering of the // result. if (rightComposite == null && sortColumns != null) node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns); // Rename the columns as specified in the SELECT node = new SubsetNode(node, subsetVars, aliases); } else { // Process the ORDER BY? if (rightComposite == null && sortColumns != null) node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns); } // Do we have a composite to merge in? if (rightComposite != null) { // For the composite node = new CompositeNode(node, rightComposite, queryExpression.CompositeFunction, queryExpression.IsCompositeAll); // Final order by? if (sortColumns != null) node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns); // Ensure a final subset node if (!(node is SubsetNode) && aliases != null) { node = new SubsetNode(node, aliases, aliases); } } return node; }
private IQueryPlanNode PlanQuery(IRequest context, SqlQueryExpression queryExpression, QueryExpressionFrom queryFrom, IList <SortColumn> sortColumns, QueryLimit limit) { // ----- Resolve the SELECT list // If there are 0 columns selected, then we assume the result should // show all of the columns in the result. bool doSubsetColumn = (queryExpression.SelectColumns.Any()); // What we are selecting var columns = BuildSelectColumns(queryExpression, queryFrom); // Prepare the column_set, var preparedColumns = columns.Prepare(context); sortColumns = ResolveOrderByRefs(preparedColumns, sortColumns); // ----- // Set up plans for each table in the from clause of the command. For // sub-queries, we recurse. var tablePlanner = CreateTablePlanner(context, queryFrom); // ----- // The WHERE and HAVING clauses var whereClause = queryExpression.WhereExpression; var havingClause = queryExpression.HavingExpression; PrepareJoins(tablePlanner, queryExpression, queryFrom, ref whereClause); // Prepare the WHERE and HAVING clause, qualifies all variables and // prepares sub-queries. whereClause = PrepareSearchExpression(context, queryFrom, whereClause); havingClause = PrepareSearchExpression(context, queryFrom, havingClause); // Any extra Aggregate functions that are part of the HAVING clause that // we need to add. This is a list of a name followed by the expression // that contains the aggregate function. var extraAggregateFunctions = new List <SqlExpression>(); if (havingClause != null) { havingClause = FilterHaving(havingClause, extraAggregateFunctions, context); } // Any GROUP BY functions, ObjectName[] groupByList; IList <SqlExpression> groupByFunctions; var gsz = ResolveGroupBy(queryExpression, queryFrom, context, out groupByList, out groupByFunctions); // Resolve GROUP MAX variable to a reference in this from set var groupmaxColumn = ResolveGroupMax(queryExpression, queryFrom); // ----- // Now all the variables should be resolved and correlated variables set // up as appropriate. // If nothing in the FROM clause then simply evaluate the result of the // select if (queryFrom.SourceCount == 0) { return(EvaluateToSingle(preparedColumns)); } // Plan the where clause. The returned node is the plan to evaluate the // WHERE clause. var node = tablePlanner.PlanSearchExpression(whereClause); SqlExpression[] defFunList; string[] defFunNames; var fsz = MakeupFunctions(preparedColumns, extraAggregateFunctions, out defFunList, out defFunNames); var groupInfo = new GroupInfo { Columns = preparedColumns, FunctionCount = fsz, FunctionNames = defFunNames, FunctionExpressions = defFunList, GroupByCount = gsz, GroupByNames = groupByList, GroupByExpressions = groupByFunctions.ToArray(), GroupMax = groupmaxColumn }; node = PlanGroup(node, groupInfo); // The result column list var selectColumns = preparedColumns.SelectedColumns.ToList(); int sz = selectColumns.Count; // Evaluate the having clause if necessary if (havingClause != null) { // Before we evaluate the having expression we must substitute all the // aliased variables. var havingExpr = havingClause; // TODO: this requires a visitor to modify the having expression havingExpr = ReplaceAliasedVariables(havingExpr, selectColumns); var source = tablePlanner.SinglePlan; source.UpdatePlan(node); node = tablePlanner.PlanSearchExpression(havingExpr); } // Do we have a composite select expression to process? IQueryPlanNode rightComposite = null; if (queryExpression.NextComposite != null) { var compositeExpr = queryExpression.NextComposite; var compositeFrom = QueryExpressionFrom.Create(context, compositeExpr); // Form the right plan rightComposite = PlanQuery(context, compositeExpr, compositeFrom, null, null); } // Do we do a final subset column? ObjectName[] aliases = null; if (doSubsetColumn) { // Make up the lists var subsetVars = new ObjectName[sz]; aliases = new ObjectName[sz]; for (int i = 0; i < sz; ++i) { SelectColumn scol = selectColumns[i]; subsetVars[i] = scol.InternalName; aliases[i] = scol.ResolvedName; } // If we are distinct then add the DistinctNode here if (queryExpression.Distinct) { node = new DistinctNode(node, subsetVars); } // Process the ORDER BY? // Note that the ORDER BY has to occur before the subset call, but // after the distinct because distinct can affect the ordering of the // result. if (rightComposite == null && sortColumns != null) { node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns); } // Rename the columns as specified in the SELECT node = new SubsetNode(node, subsetVars, aliases); } else { // Process the ORDER BY? if (rightComposite == null && sortColumns != null) { node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns); } } // Do we have a composite to merge in? if (rightComposite != null) { // For the composite node = new CompositeNode(node, rightComposite, queryExpression.CompositeFunction, queryExpression.IsCompositeAll); // Final order by? if (sortColumns != null) { node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns); } // Ensure a final subset node if (!(node is SubsetNode) && aliases != null) { node = new SubsetNode(node, aliases, aliases); } } if (limit != null) { node = new LimitNode(node, limit.Offset, limit.Count); } return(node); }