Example #1
0
        public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node)
        {
            // Check if node only consists of INNER join nodes and simple table reference nodes.
            // This algorithm assumes that the table references have been lineraized so that
            //
            // - JoinedTableReference appear on the LHS only (the last one must be NamedTableReference ovbiviously)
            // - NamedTableReference appear on the RHS only
            //
            // While scanning the node's children we create a list of all JoinedTableReferences and
            // NamedTableReferences.

            InnerJoinTableExtractor innerJoinTableExtractor = new InnerJoinTableExtractor();

            innerJoinTableExtractor.Visit(node);

            if (!innerJoinTableExtractor.ConsistsOnlyOfInnerJoinsFiltersAndTables)
            {
                node.Left  = VisitAlgebraNode(node.Left);
                node.Right = VisitAlgebraNode(node.Right);
                return(node);
            }
            else
            {
                TableAlgebraNode[] algebraNodes = innerJoinTableExtractor.GetTableNodes();
                Dictionary <TableRefBinding, TableAlgebraNode> tableRefToNodeDictionary = new Dictionary <TableRefBinding, TableAlgebraNode>();
                List <TableRefBinding> tableList = new List <TableRefBinding>();
                foreach (TableAlgebraNode algebraNode in algebraNodes)
                {
                    tableRefToNodeDictionary.Add(algebraNode.TableRefBinding, algebraNode);
                    tableList.Add(algebraNode.TableRefBinding);
                }

                // Create a mapping RowBufferEntry -> ColumnRefBinding

                Dictionary <RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary = new Dictionary <RowBufferEntry, ColumnRefBinding>();
                foreach (TableRefBinding tableRefBinding in tableList)
                {
                    foreach (ColumnRefBinding columnRefBinding in tableRefBinding.ColumnRefs)
                    {
                        rowBufferColumnDictionary.Add(columnRefBinding.ValueDefinition.Target, columnRefBinding);
                    }
                }

                // Create list of all possible join conditions and remaining AND-parts.

                List <JoinCondition>  joinConditionList = new List <JoinCondition>();
                List <ExpressionNode> andPartList       = new List <ExpressionNode>();

                ExpressionNode filter = AstUtil.CombineConditions(LogicalOperator.And, innerJoinTableExtractor.GetFilters());

                foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, filter))
                {
                    JoinCondition joinCondition = ConvertToJoinCondition(rowBufferColumnDictionary, andPart);

                    if (joinCondition != null)
                    {
                        joinConditionList.Add(joinCondition);
                    }
                    else
                    {
                        andPartList.Add(andPart);
                    }
                }

                // After creating the list of all join conditions and AND-parts we have all we need to create
                // an optimimal join order between all tables of this part of the table tree.
                JoinOrder bestJoinOrder = GetBestJoinOrder(tableList.ToArray(), joinConditionList.ToArray(), andPartList.ToArray());

                // Get all tables that are introduced by this join order

                Dictionary <RowBufferEntry, ColumnValueDefinition> introducedColumns = GetIntroducedColumns(bestJoinOrder);

                // Combine AND-part list with all unused join conditions.

                andPartList.AddRange(bestJoinOrder.UnusedConditions);

                // Now we will re-create this part of the tree using the this join order.

                AlgebraNode lastAlgebraNode = null;
                for (int joinIndex = 0; joinIndex < bestJoinOrder.Joins.Length; joinIndex++)
                {
                    Join join = bestJoinOrder.Joins[joinIndex];

                    AlgebraNode      tableInput;
                    TableAlgebraNode tableNode = tableRefToNodeDictionary[join.TableRefBinding];

                    ExpressionNode tableFilter = ExtractConditionsApplicableToTable(introducedColumns, andPartList, join.TableRefBinding);
                    if (tableFilter == null)
                    {
                        tableInput = tableNode;
                    }
                    else
                    {
                        FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode();
                        filterAlgebraNode.Input     = tableNode;
                        filterAlgebraNode.Predicate = tableFilter;
                        tableInput = filterAlgebraNode;
                    }

                    if (lastAlgebraNode == null)
                    {
                        // This was the first one.
                        lastAlgebraNode = tableInput;
                    }
                    else
                    {
                        // Not the first one, we can create a join with the current table reference
                        // and last table reference.

                        // Get all AND-parts that can be applied to the tables already joined.
                        // This expression is merged to one condition.
                        ExpressionNode[] applicableAndParts = GetAndPartsApplicableToJoin(introducedColumns, bestJoinOrder, joinIndex, andPartList, true);
                        ExpressionNode   condition          = AstUtil.CombineConditions(LogicalOperator.And, applicableAndParts);

                        ExpressionNode joinCondition;
                        if (join.JoinCondition == null)
                        {
                            joinCondition = null;
                        }
                        else
                        {
                            joinCondition = join.JoinCondition.ToExpression();
                        }

                        ExpressionNode completeCondition = AstUtil.CombineConditions(LogicalOperator.And, condition, joinCondition);

                        JoinAlgebraNode joinAlgebraNode = new JoinAlgebraNode();
                        joinAlgebraNode.Op        = JoinAlgebraNode.JoinOperator.InnerJoin;
                        joinAlgebraNode.Left      = lastAlgebraNode;
                        joinAlgebraNode.Right     = tableInput;
                        joinAlgebraNode.Predicate = completeCondition;

                        // Next time this newly created join is the last table reference.
                        lastAlgebraNode = joinAlgebraNode;
                    }
                }

                return(lastAlgebraNode);
            }
        }
Example #2
0
		public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node)
		{
			// Check if node only consists of INNER join nodes and simple table reference nodes.
			// This algorithm assumes that the table references have been lineraized so that
			//
			// - JoinedTableReference appear on the LHS only (the last one must be NamedTableReference ovbiviously)
			// - NamedTableReference appear on the RHS only
			//
			// While scanning the node's children we create a list of all JoinedTableReferences and
			// NamedTableReferences.

			InnerJoinTableExtractor innerJoinTableExtractor = new InnerJoinTableExtractor();
			innerJoinTableExtractor.Visit(node);

			if (!innerJoinTableExtractor.ConsistsOnlyOfInnerJoinsFiltersAndTables)
			{
				node.Left = VisitAlgebraNode(node.Left);
				node.Right = VisitAlgebraNode(node.Right);
				return node;                
			}
			else
			{
				TableAlgebraNode[] algebraNodes = innerJoinTableExtractor.GetTableNodes();
				Dictionary<TableRefBinding,TableAlgebraNode> tableRefToNodeDictionary = new Dictionary<TableRefBinding, TableAlgebraNode>();
				List<TableRefBinding> tableList = new List<TableRefBinding>();
				foreach (TableAlgebraNode algebraNode in algebraNodes)
				{
					tableRefToNodeDictionary.Add(algebraNode.TableRefBinding, algebraNode);
					tableList.Add(algebraNode.TableRefBinding);
				}

				// Create a mapping RowBufferEntry -> ColumnRefBinding

				Dictionary<RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary = new Dictionary<RowBufferEntry, ColumnRefBinding>();
				foreach (TableRefBinding tableRefBinding in tableList)
				{
					foreach (ColumnRefBinding columnRefBinding in tableRefBinding.ColumnRefs)
						rowBufferColumnDictionary.Add(columnRefBinding.ValueDefinition.Target, columnRefBinding);
				}

				// Create list of all possible join conditions and remaining AND-parts.

				List<JoinCondition> joinConditionList = new List<JoinCondition>();
				List<ExpressionNode> andPartList = new List<ExpressionNode>();

				ExpressionNode filter = AstUtil.CombineConditions(LogicalOperator.And, innerJoinTableExtractor.GetFilters());

				foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, filter))
				{
					JoinCondition joinCondition = ConvertToJoinCondition(rowBufferColumnDictionary, andPart);

					if (joinCondition != null)
						joinConditionList.Add(joinCondition);
					else
						andPartList.Add(andPart);
				}

				// After creating the list of all join conditions and AND-parts we have all we need to create
				// an optimimal join order between all tables of this part of the table tree.
				JoinOrder bestJoinOrder = GetBestJoinOrder(tableList.ToArray(), joinConditionList.ToArray(), andPartList.ToArray());

				// Get all tables that are introduced by this join order
                
				Dictionary<RowBufferEntry, ColumnValueDefinition> introducedColumns = GetIntroducedColumns(bestJoinOrder);

				// Combine AND-part list with all unused join conditions.

				andPartList.AddRange(bestJoinOrder.UnusedConditions);

				// Now we will re-create this part of the tree using the this join order.

				AlgebraNode lastAlgebraNode = null;
				for (int joinIndex = 0; joinIndex < bestJoinOrder.Joins.Length; joinIndex++)
				{
					Join join = bestJoinOrder.Joins[joinIndex];

					AlgebraNode tableInput;
					TableAlgebraNode tableNode = tableRefToNodeDictionary[join.TableRefBinding];

					ExpressionNode tableFilter = ExtractConditionsApplicableToTable(introducedColumns, andPartList, join.TableRefBinding);
					if (tableFilter == null)
					{
						tableInput = tableNode;
					}
					else
					{
						FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode();
						filterAlgebraNode.Input = tableNode;
						filterAlgebraNode.Predicate = tableFilter;
						tableInput = filterAlgebraNode;
					}

					if (lastAlgebraNode == null)
					{
						// This was the first one.
						lastAlgebraNode = tableInput;
					}
					else
					{
						// Not the first one, we can create a join with the current table reference
						// and last table reference.

						// Get all AND-parts that can be applied to the tables already joined.
						// This expression is merged to one condition.
						ExpressionNode[] applicableAndParts = GetAndPartsApplicableToJoin(introducedColumns, bestJoinOrder, joinIndex, andPartList, true);
						ExpressionNode condition = AstUtil.CombineConditions(LogicalOperator.And, applicableAndParts);

						ExpressionNode joinCondition;
						if (join.JoinCondition == null)
							joinCondition = null;
						else
							joinCondition = join.JoinCondition.ToExpression();

						ExpressionNode completeCondition = AstUtil.CombineConditions(LogicalOperator.And, condition, joinCondition);

						JoinAlgebraNode joinAlgebraNode = new JoinAlgebraNode();
						joinAlgebraNode.Op = JoinAlgebraNode.JoinOperator.InnerJoin;
						joinAlgebraNode.Left = lastAlgebraNode;
						joinAlgebraNode.Right = tableInput;
						joinAlgebraNode.Predicate = completeCondition;

						// Next time this newly created join is the last table reference.
						lastAlgebraNode = joinAlgebraNode;
					}
				}

				return lastAlgebraNode;
			}
		}