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)); }
protected override BoundRelation RewriteAssertRelation(BoundAssertRelation node) { _recorder.Record(node.Condition); return(base.RewriteAssertRelation(node)); }
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))); }