/// <summary> /// Naturally joins two <see cref="PlanTableSource"/> objects in this planner. /// </summary> /// <param name="plan1"></param> /// <param name="plan2"></param> /// <remarks> /// When this method returns the actual plans will be joined together. This method /// modifies <see cref="tableList"/>. /// </remarks> /// <returns></returns> private PlanTableSource NaturallyJoinPlans(PlanTableSource plan1, PlanTableSource plan2) { JoinType joinType; Expression onExpr; PlanTableSource leftPlan, rightPlan; // Are the plans linked by common join information? if (plan1.RightPlan == plan2) { joinType = plan1.RightJoinType; onExpr = plan1.RightOnExpression; leftPlan = plan1; rightPlan = plan2; } else if (plan1.LeftPlan == plan2) { joinType = plan1.LeftJoinType; onExpr = plan1.LeftOnExpression; leftPlan = plan2; rightPlan = plan1; } else { // Assertion - make sure no join clashes! if ((plan1.LeftPlan != null && plan2.LeftPlan != null) || (plan1.RightPlan != null && plan2.RightPlan != null)) { throw new Exception( "Assertion failed - plans can not be naturally join because " + "the left/right join plans clash."); } // Else we must assume a non-dependant join (not an outer join). // Perform a natural join IQueryPlanNode node1 = new NaturalJoinNode(plan1.Plan, plan2.Plan); return MergeTables(plan1, plan2, node1); } // This means plan1 and plan2 are linked by a common join and ON // expression which we evaluate now. bool outerJoin; if (joinType == JoinType.Left) { // Mark the left plan leftPlan.UpdatePlan(new MarkerNode(leftPlan.Plan, "OUTER_JOIN")); outerJoin = true; } else if (joinType == JoinType.Right) { // Mark the right plan rightPlan.UpdatePlan(new MarkerNode(rightPlan.Plan, "OUTER_JOIN")); outerJoin = true; } else if (joinType == JoinType.Inner) { // Inner join with ON expression outerJoin = false; } else { throw new Exception("Join type (" + joinType + ") is not supported."); } // Make a Planner object for joining these plans. var planner = new QueryTableSetPlanner(); planner.AddPlanTableSource(leftPlan.Copy()); planner.AddPlanTableSource(rightPlan.Copy()); // Evaluate the on expression IQueryPlanNode node = planner.LogicalEvaluate(onExpr); // If outer join add the left outer join node if (outerJoin) node = new LeftOuterJoinNode(node, "OUTER_JOIN"); // And merge the plans in this set with the new node. return MergeTables(plan1, plan2, node); }
public SubLogicExpressionPlan(QueryTableSetPlanner qtsp, Expression expression) { this.qtsp = qtsp; this.expression = expression; }
/// <summary> /// Makes an exact duplicate copy (deep clone) of this planner object. /// </summary> /// <returns></returns> private QueryTableSetPlanner Copy() { QueryTableSetPlanner copy = new QueryTableSetPlanner(); int sz = tableList.Count; for (int i = 0; i < sz; ++i) { copy.tableList.Add(tableList[i].Copy()); } // Copy the left and right links in the PlanTableSource for (int i = 0; i < sz; ++i) { PlanTableSource src = tableList[i]; PlanTableSource mod = copy.tableList[i]; // See how the left plan links to which index, if (src.LeftPlan != null) { int n = IndexOfPlanTableSource(src.LeftPlan); mod.SetLeftJoinInfo(copy.tableList[n], src.LeftJoinType, src.LeftOnExpression); } // See how the right plan links to which index, if (src.RightPlan != null) { int n = IndexOfPlanTableSource(src.RightPlan); mod.SetRightJoinInfo(copy.tableList[n], src.RightJoinType, src.RightOnExpression); } } return copy; }
public SimpleSubQueryExpressionPlan(QueryTableSetPlanner qtsp, Expression expression) { this.qtsp = qtsp; this.expression = expression; }
public StandardJoinExpressionPlan(QueryTableSetPlanner qtsp, Expression expression) { this.qtsp = qtsp; this.expression = expression; }
public SimpleSelectExpressionPlan(QueryTableSetPlanner qtsp, ObjectName singleVar, Operator op, Expression expression) { this.qtsp = qtsp; this.singleVar = singleVar; this.op = op; this.expression = expression; }
public SimpleSingleExpressionPlan(QueryTableSetPlanner qtsp, ObjectName singleVar, Expression expression) { this.qtsp = qtsp; this.singleVar = singleVar; this.expression = expression; }
public ExhaustiveSubQueryExpressionPlan(QueryTableSetPlanner qtsp, IList<ObjectName> allVars, Expression expression) { this.qtsp = qtsp; this.allVars = allVars; this.expression = expression; }
public ExhaustiveSelectExpressionPlan(QueryTableSetPlanner qtsp, Expression expression) { this.qtsp = qtsp; this.expression = expression; }
public ConstantExpressionPlan(QueryTableSetPlanner qtsp, Expression e) { this.qtsp = qtsp; expression = e; }
private static QueryTableSetPlanner SetupPlanners(IDatabaseConnection db, TableExpressionFromSet fromSet) { // Set up plans for each table in the from clause of the command. For // sub-queries, we recurse. var tablePlanner = new QueryTableSetPlanner(); for (int i = 0; i < fromSet.SetCount; ++i) { IFromTableSource table = fromSet.GetTable(i); if (table is FromTableSubQuerySource) { // This represents a sub-command in the FROM clause var sqlTable = (FromTableSubQuerySource)table; TableSelectExpression sqlExpr = sqlTable.TableExpression; TableExpressionFromSet sqlFromSet = sqlTable.FromSet; // Form a plan for evaluating the sub-command FROM IQueryPlanNode sqlPlan = FormQueryPlan(db, sqlExpr, sqlFromSet, null); // The top should always be a SubsetNode, if (sqlPlan is SubsetNode) { var subsetNode = (SubsetNode)sqlPlan; subsetNode.SetGivenName(sqlTable.AliasedName); } else { throw new Exception("Top plan is not a SubsetNode!"); } tablePlanner.AddTableSource(sqlPlan, sqlTable); } else if (table is FromTableDirectSource) { // This represents a direct referencable table in the FROM clause var dsTable = (FromTableDirectSource)table; IQueryPlanNode dsPlan = dsTable.CreateFetchQueryPlanNode(); tablePlanner.AddTableSource(dsPlan, dsTable); } else { throw new Exception("Unknown table source instance: " + table.GetType()); } } return tablePlanner; }
private static FilterExpression PrepareJoins(QueryTableSetPlanner tablePlanner, TableSelectExpression expression, TableExpressionFromSet fromSet, FilterExpression whereClause) { // Look at the join set and resolve the ON Expression to this statement JoiningSet joinSet = expression.From.JoinSet; var result = whereClause; // Perform a quick scan and see if there are any outer joins in the // expression. bool allInnerJoins = true; for (int i = 0; i < joinSet.TableCount - 1; ++i) { JoinType type = joinSet.GetJoinType(i); if (type != JoinType.Inner) allInnerJoins = false; } // Prepare the joins for (int i = 0; i < joinSet.TableCount - 1; ++i) { JoinType type = joinSet.GetJoinType(i); Expression onExpression = joinSet.GetOnExpression(i); if (allInnerJoins) { // If the whole join set is inner joins then simply move the on // expression (if there is one) to the WHERE clause. if (onExpression != null) { result = result.Append(onExpression); } } else { // Not all inner joins, if (type == JoinType.Inner && onExpression == null) { // Regular join with no ON expression, so no preparation necessary } else { // Either an inner join with an ON expression, or an outer join with // ON expression if (onExpression == null) throw new Exception("No ON expression in join."); // Resolve the on_expression onExpression = onExpression.Prepare(fromSet.ExpressionQualifier); // And set it in the planner tablePlanner.SetJoinInfoBetweenSources(i, type, onExpression); } } } return result; }