Example #1
0
		private void Join(TableRefBinding table, JoinCondition joinCondition)
		{
			_usedTableList.Add(table);
			_usedJoinConditionList.Add(joinCondition);

			if (_usedTableList.Count == _tables.Length)
			{
				// We have joined all tables, create the join order.
				//
				// First we create a list of the join conditions we used.

				List<Join> joinList = new List<Join>();

				for (int i = 0; i < _usedTableList.Count; i++)
				{
					TableRefBinding usedTable = _usedTableList[i];
					JoinCondition usedJoinCondition = _usedJoinConditionList[i];
						
					// The first entry will be null, since we do not join from anywhere 

					if (usedJoinCondition != null)
					{
						// Since we swapping the join sides according to the direction
						// we are joining from we need to create a clone. The clone
						// is a flat copy meaning that the tables and expressions
						// themselves are not cloned.

						usedJoinCondition = usedJoinCondition.Clone();

						// If the right table is not the table we are joining to
						// swap the join sides.

						if (usedJoinCondition.RightTable != usedTable)
							usedJoinCondition.SwapSides();
					}

					Join join = new Join();
					join.JoinCondition = usedJoinCondition;
					join.TableRefBinding = usedTable;

					joinList.Add(join);
				}

				// Secondly and very important: We also have to create a list of all
				// join conditions NOT used. Later theses conditions will be combined
				// with the and-parts since they must also be checked.

				List<ExpressionNode> unusedConditionList = new List<ExpressionNode>();

				foreach (JoinCondition jc in _joinConditions)
				{
					if (!_usedJoinConditionList.Contains(jc))
						unusedConditionList.Add(jc.ToExpression());
				}

				JoinOrder joinOrder = new JoinOrder();
				joinOrder.Joins = joinList.ToArray();
				joinOrder.UnusedConditions = unusedConditionList.ToArray();

				_joinOrderList.Add(joinOrder);
			}
			else
			{
				// We are not yet finished with all tables. Find next table
				// to join with.

				bool hasJoin = false;

				foreach (JoinCondition nextJoin in _joinConditions)
				{
					if (!_usedJoinConditionList.Contains(nextJoin))
					{
						TableRefBinding nextTable;

						if (_usedTableList.Contains(nextJoin.LeftTable))
						{
							nextTable = nextJoin.RightTable;
						}
						else if (_usedTableList.Contains(nextJoin.RightTable))
						{
							nextTable = nextJoin.LeftTable;
						}
						else
						{
							continue;
						}

						if (_usedTableList.Contains(nextTable))
							continue;

						Join(nextTable, nextJoin);
						hasJoin = true;
					}
				}

				if (!hasJoin)
				{
					foreach (TableRefBinding t in _tables)
					{
						if (!_usedTableList.Contains(t))
							Join(t, null);
					}
				}
			}

			_usedJoinConditionList.RemoveAt(_usedJoinConditionList.Count - 1);
			_usedTableList.RemoveAt(_usedTableList.Count - 1);
		}
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);
            }
        }
        private void Join(TableRefBinding table, JoinCondition joinCondition)
        {
            _usedTableList.Add(table);
            _usedJoinConditionList.Add(joinCondition);

            if (_usedTableList.Count == _tables.Length)
            {
                // We have joined all tables, create the join order.
                //
                // First we create a list of the join conditions we used.

                List <Join> joinList = new List <Join>();

                for (int i = 0; i < _usedTableList.Count; i++)
                {
                    TableRefBinding usedTable         = _usedTableList[i];
                    JoinCondition   usedJoinCondition = _usedJoinConditionList[i];

                    // The first entry will be null, since we do not join from anywhere

                    if (usedJoinCondition != null)
                    {
                        // Since we swapping the join sides according to the direction
                        // we are joining from we need to create a clone. The clone
                        // is a flat copy meaning that the tables and expressions
                        // themselves are not cloned.

                        usedJoinCondition = usedJoinCondition.Clone();

                        // If the right table is not the table we are joining to
                        // swap the join sides.

                        if (usedJoinCondition.RightTable != usedTable)
                        {
                            usedJoinCondition.SwapSides();
                        }
                    }

                    Join join = new Join();
                    join.JoinCondition   = usedJoinCondition;
                    join.TableRefBinding = usedTable;

                    joinList.Add(join);
                }

                // Secondly and very important: We also have to create a list of all
                // join conditions NOT used. Later theses conditions will be combined
                // with the and-parts since they must also be checked.

                List <ExpressionNode> unusedConditionList = new List <ExpressionNode>();

                foreach (JoinCondition jc in _joinConditions)
                {
                    if (!_usedJoinConditionList.Contains(jc))
                    {
                        unusedConditionList.Add(jc.ToExpression());
                    }
                }

                JoinOrder joinOrder = new JoinOrder();
                joinOrder.Joins            = joinList.ToArray();
                joinOrder.UnusedConditions = unusedConditionList.ToArray();

                _joinOrderList.Add(joinOrder);
            }
            else
            {
                // We are not yet finished with all tables. Find next table
                // to join with.

                bool hasJoin = false;

                foreach (JoinCondition nextJoin in _joinConditions)
                {
                    if (!_usedJoinConditionList.Contains(nextJoin))
                    {
                        TableRefBinding nextTable;

                        if (_usedTableList.Contains(nextJoin.LeftTable))
                        {
                            nextTable = nextJoin.RightTable;
                        }
                        else if (_usedTableList.Contains(nextJoin.RightTable))
                        {
                            nextTable = nextJoin.LeftTable;
                        }
                        else
                        {
                            continue;
                        }

                        if (_usedTableList.Contains(nextTable))
                        {
                            continue;
                        }

                        Join(nextTable, nextJoin);
                        hasJoin = true;
                    }
                }

                if (!hasJoin)
                {
                    foreach (TableRefBinding t in _tables)
                    {
                        if (!_usedTableList.Contains(t))
                        {
                            Join(t, null);
                        }
                    }
                }
            }

            _usedJoinConditionList.RemoveAt(_usedJoinConditionList.Count - 1);
            _usedTableList.RemoveAt(_usedTableList.Count - 1);
        }