private Iterator BuildAssert(BoundAssertRelation relation)
        {
            var input      = BuildRelation(relation.Input);
            var allocation = BuildRowBufferAllocation(relation.Input, input.RowBuffer);
            var predicate  = BuildPredicate(relation.Condition, true, allocation);

            return(new AssertIterator(input, predicate, relation.Message));
        }
        protected override BoundExpression RewriteSingleRowSubselect(BoundSingleRowSubselect node)
        {
            var relation = RewriteRelation(node.Relation);

            var factory = node.Value.Factory;

            // TODO: If the query is guranteed to return a single, e.g. if it is a aggregated but not grouped,
            //       we should not emit the additional aggregation and assertion.

            // 1. We need to know whether it returns more then one row.

            var valueSlot   = node.Value;
            var anyOutput   = factory.CreateTemporary(valueSlot.Type);
            var countOutput = factory.CreateTemporary(typeof(int));

            var anyAggregateSymbol = BuiltInAggregates.Any;
            var anyAggregatable    = anyAggregateSymbol.Definition.CreateAggregatable(valueSlot.Type);

            var countAggregatedSymbol = BuiltInAggregates.Count;
            var countAggregatable     = countAggregatedSymbol.Definition.CreateAggregatable(typeof(int));

            var aggregates = new[]
            {
                new BoundAggregatedValue(anyOutput, anyAggregateSymbol, anyAggregatable, Expression.Value(valueSlot)),
                new BoundAggregatedValue(countOutput, countAggregatedSymbol, countAggregatable, Expression.Literal(0))
            };

            var aggregation = new BoundGroupByAndAggregationRelation(relation, Enumerable.Empty <BoundComparedValue>(), aggregates);

            // 2. Now we can assert that the number of rows returned is at most one.

            var condition = Expression.LessThan(Expression.Value(countOutput), Expression.Literal(1));

            var message        = Resources.SubqueryReturnedMoreThanRow;
            var assertRelation = new BoundAssertRelation(aggregation, condition, message);

            var subquery   = new Subquery(SubqueryKind.Subselect, anyOutput, assertRelation, CurrentPassthru);
            var subqueries = _subqueryStack.Peek();

            subqueries.Add(subquery);

            return(Expression.Value(anyOutput));
        }
 private static CardinalityEstimate EstimateAssertRelation(BoundAssertRelation relation)
 {
     // TODO: If we knew more about the asser (such as MAX(1) or MAX(100)) we'd be able to give better estimates.
     return(Estimate(relation.Input));
 }
Beispiel #4
0
        protected override BoundRelation RewriteAssertRelation(BoundAssertRelation node)
        {
            _recorder.Record(node.Condition);

            return(base.RewriteAssertRelation(node));
        }
Beispiel #5
0
        private BoundRelation InstantiateRecursiveCommonTableExpression(ImmutableArray <ValueSlot> outputValues, CommonTableExpressionSymbol symbol)
        {
            // TableSpoolPusher
            //     Concat
            //         Compute (Recursion := 0)
            //             <Anchor>
            //         Assert (Recursion <= 100)
            //             Inner Join
            //                 Compute (Recursion := Recursion + 1)
            //                     TableSpoolPopper
            //                 Concat
            //                      Filter <RecursiveJoinPredicate1>
            //                          <RecursiveMember1>
            //                      Filter <RecursiveJoinPredicate2>
            //                          <RecursiveMember2>

            var valueSlotFactory = outputValues.First().Factory;

            // Create output values

            var unionRecusionSlot = valueSlotFactory.CreateTemporary(typeof(int));
            var concatValueSlots  = outputValues.Add(unionRecusionSlot);

            // Create anchor

            var anchor       = RewriteRelation(Instatiator.Instantiate(symbol.Anchor.Relation));
            var anchorValues = anchor.GetOutputValues().ToImmutableArray();

            var initRecursionSlot       = valueSlotFactory.CreateTemporary(typeof(int));
            var initRecursionDefinition = new BoundComputedValue(Expression.Literal(0), initRecursionSlot);
            var initRecursion           = new BoundComputeRelation(anchor, ImmutableArray.Create(initRecursionDefinition));

            var initRecursionOutputs = anchorValues.Add(initRecursionSlot);

            // Create TableSpoolPopper

            var tableSpoolPopperSlots = initRecursionOutputs.Select(v => v.Duplicate()).ToImmutableArray();

            var tableSpoolPopper = new BoundTableSpoolPopper(tableSpoolPopperSlots);

            var anchorRecursionCounter = tableSpoolPopperSlots.Last();
            var inc = Expression.Plus(Expression.Value(anchorRecursionCounter), Expression.Literal(1));
            var incRecursionSlot       = valueSlotFactory.CreateTemporary(typeof(int));
            var incRecursionDefinition = new BoundComputedValue(inc, incRecursionSlot);
            var incRecursion           = new BoundComputeRelation(tableSpoolPopper, ImmutableArray.Create(incRecursionDefinition));

            // Create recursive members

            var recursiveRewriter      = new CommonTableExpressionInstantiator(symbol);
            var recursiveMembers       = new List <BoundRelation>(symbol.RecursiveMembers.Length);
            var recursiveMemberOutputs = new List <ImmutableArray <ValueSlot> >(symbol.RecursiveMembers.Length);

            var anchorReferences = tableSpoolPopperSlots.RemoveAt(tableSpoolPopperSlots.Length - 1);

            foreach (var recursiveMember in symbol.RecursiveMembers)
            {
                var recursivePrototype       = recursiveMember.Relation;
                var mapping                  = CreateRecursiveMemberInstanceValueSlotMapping(symbol, anchorReferences, recursivePrototype);
                var recursiveInstance        = Instatiator.Instantiate(recursivePrototype, mapping);
                var recursiveRelation        = recursiveRewriter.RewriteRelation(recursiveInstance);
                var recursiveRelationOutputs = recursiveRelation.GetOutputValues().ToImmutableArray();
                recursiveMembers.Add(recursiveRelation);
                recursiveMemberOutputs.Add(recursiveRelationOutputs);
            }

            // Concatenate recursive members

            var recursiveConcatValues = Enumerable
                                        .Range(0, concatValueSlots.Length - 1)
                                        .Select(i =>
            {
                var slot = valueSlotFactory.CreateTemporary(concatValueSlots[i].Type);
                return(new BoundUnifiedValue(slot, recursiveMemberOutputs.Select(o => o[i])));
            })
                                        .ToImmutableArray();

            var hasSingleRecursiveMember = recursiveMembers.Count == 1;

            var recursiveConcat  = hasSingleRecursiveMember ? recursiveMembers.Single() : new BoundConcatenationRelation(recursiveMembers, recursiveConcatValues);
            var recursionOutputs = hasSingleRecursiveMember ? recursiveMemberOutputs.Single() : recursiveConcatValues.Select(u => u.ValueSlot).ToImmutableArray();

            // Create inner join

            var join                = new BoundJoinRelation(BoundJoinType.Inner, incRecursion, recursiveConcat, null, null, null);
            var joinOutputs         = recursionOutputs.Add(incRecursionSlot);
            var recursiveProjection = new BoundProjectRelation(join, joinOutputs);

            // Create assert

            var assertCondition = Expression.LessThan(Expression.Value(incRecursionSlot), Expression.Literal(100));
            var assert          = new BoundAssertRelation(recursiveProjection, assertCondition, Resources.MaximumRecursionLevelExceeded);

            // Create top level concat

            var concatValues = concatValueSlots.Select((v, i) =>
            {
                var slots = new[]
                {
                    initRecursionOutputs[i],
                    joinOutputs[i]
                };

                return(new BoundUnifiedValue(v, slots));
            });

            var concatInputs = new BoundRelation[] { initRecursion, assert };
            var concat       = new BoundConcatenationRelation(concatInputs, concatValues);

            var tableSpoolPusher = new BoundTableSpoolPusher(concat);

            return(new BoundProjectRelation(tableSpoolPusher, concatValueSlots.Take(concatValueSlots.Length - 1)));
        }