예제 #1
0
        /// <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);
        }
예제 #2
0
 public SubLogicExpressionPlan(QueryTableSetPlanner qtsp, Expression expression)
 {
     this.qtsp = qtsp;
     this.expression = expression;
 }
예제 #3
0
        /// <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;
        }
예제 #4
0
 public SimpleSubQueryExpressionPlan(QueryTableSetPlanner qtsp, Expression expression)
 {
     this.qtsp = qtsp;
     this.expression = expression;
 }
예제 #5
0
 public StandardJoinExpressionPlan(QueryTableSetPlanner qtsp, Expression expression)
 {
     this.qtsp = qtsp;
     this.expression = expression;
 }
예제 #6
0
 public SimpleSelectExpressionPlan(QueryTableSetPlanner qtsp, ObjectName singleVar, Operator op, Expression expression)
 {
     this.qtsp = qtsp;
     this.singleVar = singleVar;
     this.op = op;
     this.expression = expression;
 }
예제 #7
0
 public SimpleSingleExpressionPlan(QueryTableSetPlanner qtsp, ObjectName singleVar, Expression expression)
 {
     this.qtsp = qtsp;
     this.singleVar = singleVar;
     this.expression = expression;
 }
예제 #8
0
 public ExhaustiveSubQueryExpressionPlan(QueryTableSetPlanner qtsp, IList<ObjectName> allVars, Expression expression)
 {
     this.qtsp = qtsp;
     this.allVars = allVars;
     this.expression = expression;
 }
예제 #9
0
 public ExhaustiveSelectExpressionPlan(QueryTableSetPlanner qtsp, Expression expression)
 {
     this.qtsp = qtsp;
     this.expression = expression;
 }
예제 #10
0
 public ConstantExpressionPlan(QueryTableSetPlanner qtsp, Expression e)
 {
     this.qtsp = qtsp;
     expression = e;
 }
예제 #11
0
        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;
        }
예제 #12
0
        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;
        }