示例#1
0
        protected override IEnumerable <Entity> ExecuteInternal(IDictionary <string, DataSource> dataSources, IQueryExecutionOptions options, IDictionary <string, Type> parameterTypes, IDictionary <string, object> parameterValues)
        {
            // https://sqlserverfast.com/epr/merge-join/
            // Implemented inner, left outer, right outer and full outer variants
            // Not implemented semi joins
            // TODO: Handle many-to-many joins
            // TODO: Handle union & concatenate

            // Left & Right: GetNext, mark as unmatched
            var leftSchema             = LeftSource.GetSchema(dataSources, parameterTypes);
            var rightSchema            = RightSource.GetSchema(dataSources, parameterTypes);
            var left                   = LeftSource.Execute(dataSources, options, parameterTypes, parameterValues).GetEnumerator();
            var right                  = RightSource.Execute(dataSources, options, parameterTypes, parameterValues).GetEnumerator();
            var mergedSchema           = GetSchema(dataSources, parameterTypes, true);
            var additionalJoinCriteria = AdditionalJoinCriteria?.Compile(mergedSchema, parameterTypes);

            var hasLeft      = left.MoveNext();
            var hasRight     = right.MoveNext();
            var leftMatched  = false;
            var rightMatched = false;

            var lt = new BooleanComparisonExpression
            {
                FirstExpression  = LeftAttribute,
                ComparisonType   = BooleanComparisonType.LessThan,
                SecondExpression = RightAttribute
            }.Compile(mergedSchema, parameterTypes);

            var eq = new BooleanComparisonExpression
            {
                FirstExpression  = LeftAttribute,
                ComparisonType   = BooleanComparisonType.Equals,
                SecondExpression = RightAttribute
            }.Compile(mergedSchema, parameterTypes);

            var gt = new BooleanComparisonExpression
            {
                FirstExpression  = LeftAttribute,
                ComparisonType   = BooleanComparisonType.GreaterThan,
                SecondExpression = RightAttribute
            }.Compile(mergedSchema, parameterTypes);

            while (!Done(hasLeft, hasRight))
            {
                // Compare key values
                var merged = Merge(hasLeft ? left.Current : null, leftSchema, hasRight ? right.Current : null, rightSchema);

                var isLt = lt(merged, parameterValues, options);
                var isEq = eq(merged, parameterValues, options);
                var isGt = gt(merged, parameterValues, options);

                if (isLt || (hasLeft && !hasRight))
                {
                    if (!leftMatched && (JoinType == QualifiedJoinType.LeftOuter || JoinType == QualifiedJoinType.FullOuter))
                    {
                        yield return(Merge(left.Current, leftSchema, null, rightSchema));
                    }

                    hasLeft     = left.MoveNext();
                    leftMatched = false;
                }
                else if (isEq)
                {
                    if ((!leftMatched || !SemiJoin) && (additionalJoinCriteria == null || additionalJoinCriteria(merged, parameterValues, options) == true))
                    {
                        yield return(merged);
                    }

                    leftMatched = true;

                    hasRight     = right.MoveNext();
                    rightMatched = false;
                }
                else if (hasRight)
                {
                    if (!rightMatched && (JoinType == QualifiedJoinType.RightOuter || JoinType == QualifiedJoinType.FullOuter))
                    {
                        yield return(Merge(null, leftSchema, right.Current, rightSchema));
                    }

                    hasRight     = right.MoveNext();
                    rightMatched = false;
                }
            }
        }
示例#2
0
        protected override IEnumerable <Entity> ExecuteInternal(IDictionary <string, DataSource> dataSources, IQueryExecutionOptions options, IDictionary <string, Type> parameterTypes, IDictionary <string, object> parameterValues)
        {
            _hashTable = new Dictionary <object, List <OuterRecord> >();
            var mergedSchema           = GetSchema(dataSources, parameterTypes, true);
            var additionalJoinCriteria = AdditionalJoinCriteria?.Compile(mergedSchema, parameterTypes);

            // Build the hash table
            var leftSchema = LeftSource.GetSchema(dataSources, parameterTypes);

            leftSchema.ContainsColumn(LeftAttribute.GetColumnName(), out var leftCol);

            foreach (var entity in LeftSource.Execute(dataSources, options, parameterTypes, parameterValues))
            {
                var key = entity[leftCol];

                if (!_hashTable.TryGetValue(key, out var list))
                {
                    list            = new List <OuterRecord>();
                    _hashTable[key] = list;
                }

                list.Add(new OuterRecord {
                    Entity = entity
                });
            }

            // Probe the hash table using the right source
            var rightSchema = RightSource.GetSchema(dataSources, parameterTypes);

            rightSchema.ContainsColumn(RightAttribute.GetColumnName(), out var rightCol);

            foreach (var entity in RightSource.Execute(dataSources, options, parameterTypes, parameterValues))
            {
                var key     = entity[rightCol];
                var matched = false;

                if (_hashTable.TryGetValue(key, out var list))
                {
                    foreach (var left in list)
                    {
                        if (SemiJoin && left.Used)
                        {
                            continue;
                        }

                        var merged = Merge(left.Entity, leftSchema, entity, rightSchema);

                        if (additionalJoinCriteria == null || additionalJoinCriteria(merged, parameterValues, options))
                        {
                            yield return(merged);

                            left.Used = true;
                            matched   = true;
                        }
                    }
                }

                if (!matched && (JoinType == QualifiedJoinType.RightOuter || JoinType == QualifiedJoinType.FullOuter))
                {
                    yield return(Merge(null, leftSchema, entity, rightSchema));
                }
            }

            if (JoinType == QualifiedJoinType.LeftOuter || JoinType == QualifiedJoinType.FullOuter)
            {
                foreach (var unmatched in _hashTable.SelectMany(kvp => kvp.Value).Where(e => !e.Used))
                {
                    yield return(Merge(unmatched.Entity, leftSchema, null, rightSchema));
                }
            }
        }