public override void Visit(UnnestOp op, Node n) { VisitRelOpDefault(op, n); var newVar = Map(op.Var); if (newVar != op.Var) { n.Op = m_command.CreateUnnestOp(newVar, op.Table); } }
/// <summary> /// If the unnestOp's var is defined as a reference of a group aggregate var, /// then the columns it produces should be registered too, but as 'unnested' references /// </summary> /// <param name="op">the unnestOp</param> /// <param name="n">current subtree</param> /// <returns>modified subtree</returns> public override void Visit(UnnestOp op, Node n) { VisitDefault(n); GroupAggregateVarRefInfo groupAggregateVarRefInfo; if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(op.Var, out groupAggregateVarRefInfo)) { PlanCompiler.Assert(op.Table.Columns.Count == 1, "Expected one column before NTE"); _groupAggregateVarInfoManager.Add(op.Table.Columns[0], groupAggregateVarRefInfo.GroupAggregateVarInfo, groupAggregateVarRefInfo.Computation, true); } }
public override void Visit(UnnestOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.VisitRelOpDefault((RelOp)op, n); Var v = this.Map(op.Var); if (v == op.Var) { return; } n.Op = (Op)this.m_command.CreateUnnestOp(v, op.Table); }
public override System.Data.Entity.Core.Query.InternalTrees.Node Visit(UnnestOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.VisitChildren(n); List <System.Data.Entity.Core.Query.InternalTrees.Node> subqueries; if (this.m_nodeSubqueries.TryGetValue(n, out subqueries)) { return(this.AugmentWithSubqueries(n, subqueries, false)); } return(n); }
/// <summary> /// Build up an unnest above a scalar op node /// X => unnest(X) /// </summary> /// <param name="collectionNode">the scalarop collection node</param> /// <returns>the unnest node</returns> private Node BuildUnnest(Node collectionNode) { PlanCompiler.Assert(collectionNode.Op.IsScalarOp, "non-scalar usage of Unnest?"); PlanCompiler.Assert(TypeSemantics.IsCollectionType(collectionNode.Op.Type), "non-collection usage for Unnest?"); Var newVar; Node varDefNode = m_command.CreateVarDefNode(collectionNode, out newVar); UnnestOp unnestOp = m_command.CreateUnnestOp(newVar); Node unnestNode = m_command.CreateNode(unnestOp, varDefNode); return(unnestNode); }
public override void Visit(UnnestOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.VisitDefault(n); GroupAggregateVarRefInfo groupAggregateVarRefInfo; if (!this._groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(op.Var, out groupAggregateVarRefInfo)) { return; } System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(op.Table.Columns.Count == 1, "Expected one column before NTE"); this._groupAggregateVarInfoManager.Add(op.Table.Columns[0], groupAggregateVarRefInfo.GroupAggregateVarInfo, groupAggregateVarRefInfo.Computation, true); }
/// <summary> /// Converts the reference to a TVF as following: Collect(PhysicalProject(Unnest(Func))) /// </summary> /// <param name="op">current function op</param> /// <param name="n">current function subtree</param> /// <returns>the new expression that corresponds to the TVF</returns> private Node VisitCollectionFunction(FunctionOp op, Node n) { PlanCompiler.Assert(TypeSemantics.IsCollectionType(op.Type), "non-TVF function?"); Node unnestNode = BuildUnnest(n); UnnestOp unnestOp = unnestNode.Op as UnnestOp; PhysicalProjectOp projectOp = m_command.CreatePhysicalProjectOp(unnestOp.Table.Columns[0]); Node projectNode = m_command.CreateNode(projectOp, unnestNode); CollectOp collectOp = m_command.CreateCollectOp(n.Op.Type); Node collectNode = m_command.CreateNode(collectOp, projectNode); return(collectNode); }
/// <summary> /// Converts a collection aggregate function count(X), where X is a collection into /// two parts. Part A is a groupby subquery that looks like /// GroupBy(Unnest(X), empty, count(y)) /// where "empty" describes the fact that the groupby has no keys, and y is an /// element var of the Unnest /// /// Part 2 is a VarRef that refers to the aggregate var for count(y) described above. /// /// Logically, we would replace the entire functionOp by element(GroupBy...). However, /// since we also want to translate element() into single-row-subqueries, we do this /// here as well. /// /// The function itself is replaced by the VarRef, and the GroupBy is added to the list /// of scalar subqueries for the current relOp node on the stack /// /// </summary> /// <param name="op">the functionOp for the collection agg</param> /// <param name="n">current subtree</param> /// <returns>the VarRef node that should replace the function</returns> private Node VisitCollectionAggregateFunction(FunctionOp op, Node n) { TypeUsage softCastType = null; Node argNode = n.Child0; if (OpType.SoftCast == argNode.Op.OpType) { softCastType = TypeHelpers.GetEdmType <CollectionType>(argNode.Op.Type).TypeUsage; argNode = argNode.Child0; while (OpType.SoftCast == argNode.Op.OpType) { argNode = argNode.Child0; } } Node unnestNode = BuildUnnest(argNode); UnnestOp unnestOp = unnestNode.Op as UnnestOp; Var unnestOutputVar = unnestOp.Table.Columns[0]; AggregateOp aggregateOp = m_command.CreateAggregateOp(op.Function, false); VarRefOp unnestVarRefOp = m_command.CreateVarRefOp(unnestOutputVar); Node unnestVarRefNode = m_command.CreateNode(unnestVarRefOp); if (softCastType != null) { unnestVarRefNode = m_command.CreateNode(m_command.CreateSoftCastOp(softCastType), unnestVarRefNode); } Node aggExprNode = m_command.CreateNode(aggregateOp, unnestVarRefNode); VarVec keyVars = m_command.CreateVarVec(); // empty keys Node keyVarDefListNode = m_command.CreateNode(m_command.CreateVarDefListOp()); VarVec gbyOutputVars = m_command.CreateVarVec(); Var aggVar; Node aggVarDefListNode = m_command.CreateVarDefListNode(aggExprNode, out aggVar); gbyOutputVars.Set(aggVar); GroupByOp gbyOp = m_command.CreateGroupByOp(keyVars, gbyOutputVars); Node gbySubqueryNode = m_command.CreateNode(gbyOp, unnestNode, keyVarDefListNode, aggVarDefListNode); // "Move" this subquery to my parent relop Node ret = AddSubqueryToParentRelOp(aggVar, gbySubqueryNode); return(ret); }
/// <summary> /// Visitor for UnnestOp. If the child has any subqueries, we need to convert this /// into an /// OuterApply(S, Unnest) /// unlike the other cases where the OuterApply will appear as the input of the node /// </summary> /// <param name="op">the unnestOp</param> /// <param name="n">current subtree</param> /// <returns>modified subtree</returns> public override Node Visit(UnnestOp op, Node n) { VisitChildren(n); // visit all my children first List <Node> nestedSubqueries; if (m_nodeSubqueries.TryGetValue(n, out nestedSubqueries)) { // We pass 'inputFirst = false' since the subqueries contribute to the driver in the unnest, // they are not generated by the unnest. Node newNode = AugmentWithSubqueries(n, nestedSubqueries, false /* inputFirst */); return(newNode); } else { return(n); } }
public override Node Visit(UnnestOp op, Node n) { // Visit the children first VisitChildren(n); Var newUnnestVar = null; md.EdmFunction processingTVF = null; if (n.HasChild0) { var chi = n.Child0; var varDefOp = chi.Op as VarDefOp; if (null != varDefOp) { if (TypeUtils.IsCollectionType(varDefOp.Var.Type)) { var computedVar = (ComputedVar)varDefOp.Var; if (chi.HasChild0 && chi.Child0.Op.OpType == OpType.Function) { // For a TVF function call use the original non-flattened variable: // the function will not return properties described in the flattened type, there would be no null sentinel and // row prop names will be as declared in the function signature. // The mismatch between the flattened type and the orignial type is fixed by wrapping into a ProjectOp produced by CreateTVFProjection(...). newUnnestVar = computedVar; processingTVF = ((FunctionOp)chi.Child0.Op).Function; } else { // Flatten the computer var and add it to m_varInfoMap. var newChildren = new List<Node>(); md.TypeUsage newType; FlattenComputedVar(computedVar, chi, out newChildren, out newType); PlanCompiler.Assert(newChildren.Count == 1, "Flattening unnest var produced more than one Var."); n.Child0 = newChildren[0]; } } } } if (processingTVF != null) { PlanCompiler.Assert(newUnnestVar != null, "newUnnestVar must be initialized in the TVF case."); } else { // Fetch the new unnestVar that should have been prepared inside the FlattenComputedVar call above. // If the new var info is not ready then the shape of the unnest or the variable type is incorrect. VarInfo unnestVarInfo; if (m_varInfoMap.TryGetVarInfo(op.Var, out unnestVarInfo) && unnestVarInfo.Kind == VarInfoKind.CollectionVarInfo) { newUnnestVar = ((CollectionVarInfo)unnestVarInfo).NewVar; } else { throw new InvalidOperationException(Strings.ADP_InternalProviderError((int)EntityUtil.InternalErrorCode.WrongVarType)); } } // If the type of table column var representing the collection element is not structured, simply update the n.Op with the new var and return n. // Otherwise rebuild the UnnestOp based on the new flattened type of the new input var fetched above. // If the input var represents a TVF call, then wrap the newly rebuilt UnnestOp into a ProjectOp (see below for more details). var unnestTableColumnVar = op.Table.Columns[0]; if (!TypeUtils.IsStructuredType(unnestTableColumnVar.Type)) { PlanCompiler.Assert( processingTVF == null, "TVFs returning a collection of values of a non-structured type are not supported"); if (md.TypeSemantics.IsEnumerationType(unnestTableColumnVar.Type) || md.TypeSemantics.IsStrongSpatialType(unnestTableColumnVar.Type)) { var unnestOp = m_command.CreateUnnestOp(newUnnestVar); m_varInfoMap.CreatePrimitiveTypeVarInfo(unnestTableColumnVar, unnestOp.Table.Columns[0]); n.Op = unnestOp; } else { // Update the current unnest node with the new UnnestOp based on the newUnnestVar and the old table. n.Op = m_command.CreateUnnestOp(newUnnestVar, op.Table); } } else { // // 1. Flatten out the table to be used in the new UnnestOp. // If processingTVF use the typeInfo.FlattenedType for the new table structure, // otherwise use the original type of the unnestTableColumnVar representing precisely the fields returned by the TVF. // // 2. Create the new UnnestOp using the new unnest input var and the new table. // Note that if processingTVF, the new unnest input var is not flattened (see code above for more info). // // 3. If processingTVF, create a ProjectOp and wrap the new UnnestOp into it. // The new ProjectOp projects fields of the typeInfo.FlattenedType. The values of the projected fields // are taken from the corresponding variables of the new UnnestOp. // The new ProjectOp also projects a null sentinenel if the flattened type has one. // // 4. Update m_varInfoMap with the new new entry that maps the old unnestTableColumnVar to the list of new flattened vars: // If processingTVF, the new flattended vars are the outputs of the ProjectOp, // otherwise the new flattened vars are the columns on the new UnnestOp.Table. // // // Get the flattened representation of the table column var type. // var typeInfo = m_typeInfo.GetTypeInfo(unnestTableColumnVar.Type); TableMD newTableMetadata; if (processingTVF != null) { // For the direct function call use the original non-flattened type. // The function will not return values according to the flattened type: // there would be no null sentinel and row prop names will be as declared in the function signature. // In the code below we create a projection over the function call that produces the flattened. var tvfReturnType = TypeHelpers.GetTvfReturnType(processingTVF); PlanCompiler.Assert( Command.EqualTypes(tvfReturnType, unnestTableColumnVar.Type.EdmType), "Unexpected TVF return type (row type is expected)."); newTableMetadata = m_command.CreateFlatTableDefinition(tvfReturnType.Properties, GetTvfResultKeys(processingTVF), null); } else { newTableMetadata = m_command.CreateFlatTableDefinition(typeInfo.FlattenedType); } var newTable = m_command.CreateTableInstance(newTableMetadata); // Update the current unnest node with the new UnnestOp based on the newUnnestVar and newTable. n.Op = m_command.CreateUnnestOp(newUnnestVar, newTable); List<Var> newVars; if (processingTVF != null) { // Replace the current Unnest(Func()) with the new Project(Unnest(Func())) n = CreateTVFProjection(n, newTable.Columns, typeInfo, out newVars); } else { newVars = newTable.Columns; } // Map the unnestTableColumnVar to the list of the new flattened vars. m_varInfoMap.CreateStructuredVarInfo( unnestTableColumnVar, typeInfo.FlattenedType, newVars, typeInfo.FlattenedType.Properties.ToList()); } return n; }
/// <summary> /// Visitor for UnnestOp. If the child has any subqueries, we need to convert this /// into an /// OuterApply(S, Unnest) /// unlike the other cases where the OuterApply will appear as the input of the node /// </summary> /// <param name="op"> the unnestOp </param> /// <param name="n"> current subtree </param> /// <returns> modified subtree </returns> public override Node Visit(UnnestOp op, Node n) { VisitChildren(n); // visit all my children first List<Node> nestedSubqueries; if (m_nodeSubqueries.TryGetValue(n, out nestedSubqueries)) { // We pass 'inputFirst = false' since the subqueries contribute to the driver in the unnest, // they are not generated by the unnest. var newNode = AugmentWithSubqueries(n, nestedSubqueries, false /* inputFirst */); return newNode; } else { return n; } }
public override void Visit(UnnestOp op, Node n) { VisitRelOpDefault(op, n); AssertOpType(n.Child0.Op, OpType.VarDef); }
/// <summary> /// If the Subtree rooted at the collect is of the following structure: /// /// PhysicalProject(outputVar) /// | /// Project(s) /// | /// Unnest /// /// where the unnest is over the group aggregate var and the output var /// is either a reference to the group aggregate var or to a constant, it returns the /// translation of the ouput var. /// </summary> /// <param name="n"></param> /// <returns></returns> private Node VisitCollect(Node n) { //Make sure the only children are projects over unnest Node currentNode = n.Child0; Dictionary <Var, Node> constantDefinitions = new Dictionary <Var, Node>(); while (currentNode.Child0.Op.OpType == OpType.Project) { currentNode = currentNode.Child0; //Visit the VarDefListOp child if (VisitDefault(currentNode.Child1) == null) { return(null); } foreach (Node definitionNode in currentNode.Child1.Children) { if (IsConstant(definitionNode.Child0)) { constantDefinitions.Add(((VarDefOp)definitionNode.Op).Var, definitionNode.Child0); } } } if (currentNode.Child0.Op.OpType != OpType.Unnest) { return(null); } // Handle the unnest UnnestOp unnestOp = (UnnestOp)currentNode.Child0.Op; GroupAggregateVarRefInfo groupAggregateVarRefInfo; if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(unnestOp.Var, out groupAggregateVarRefInfo)) { if (_targetGroupAggregateVarInfo == null) { _targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo; } else if (_targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo) { return(null); } if (!_isUnnested) { return(null); } } else { return(null); } PhysicalProjectOp physicalProjectOp = (PhysicalProjectOp)n.Child0.Op; PlanCompiler.Assert(physicalProjectOp.Outputs.Count == 1, "PhysicalProject should only have one output at this stage"); Var outputVar = physicalProjectOp.Outputs[0]; Node computationTemplate = TranslateOverGroupAggregateVar(outputVar, null); if (computationTemplate != null) { _isUnnested = true; return(computationTemplate); } Node constantDefinitionNode; if (constantDefinitions.TryGetValue(outputVar, out constantDefinitionNode)) { _isUnnested = true; return(constantDefinitionNode); } return(null); }
public override void Visit(UnnestOp op, Node n) { VisitRelOpDefault(op, n); Var newVar = Map(op.Var); if (newVar != op.Var) { n.Op = m_command.CreateUnnestOp(newVar, op.Table); } }
public override void Visit(UnnestOp op, Node n) { VisitDefault(n); GroupAggregateVarRefInfo groupAggregateVarRefInfo; if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(op.Var, out groupAggregateVarRefInfo)) { PlanCompiler.Assert(op.Table.Columns.Count == 1, "Expected one column before NTE"); _groupAggregateVarInfoManager.Add( op.Table.Columns[0], groupAggregateVarRefInfo.GroupAggregateVarInfo, groupAggregateVarRefInfo.Computation, true); } }
public override System.Data.Entity.Core.Query.InternalTrees.Node Visit(UnnestOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.AddReference(op.Var); this.VisitChildren(n); return(n); }
/// <summary> /// Visitor pattern method for UnnestOp /// </summary> /// <param name="op"> The UnnestOp being visited </param> /// <param name="n"> The Node that references the Op </param> public virtual void Visit(UnnestOp op, Node n) { VisitRelOpDefault(op, n); }
/// <summary> /// UnnestOp /// Marks the unnestVar as referenced, and if there /// is a child, visits the child. /// </summary> /// <param name="op"> the unnestOp </param> /// <param name="n"> current subtree </param> /// <returns> modified subtree </returns> public override Node Visit(UnnestOp op, Node n) { AddReference(op.Var); VisitChildren(n); // visit my vardefop - defining the unnest var(if any) return(n); }
public override void Visit(UnnestOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.VisitChildren(n); }
public override Node Visit(UnnestOp op, Node n) { #if DEBUG var input = Dump.ToXml(n); #endif //DEBUG // First, visit my children VisitChildren(n); // If we're unnesting a UDT, then simply return - we cannot eliminate this unnest // It must be handled by the store var collType = TypeHelpers.GetEdmType<md.CollectionType>(op.Var.Type); // Find the VarDef node for the var we're supposed to unnest. PlanCompiler.Assert(n.Child0.Op.OpType == OpType.VarDef, "Un-nest without VarDef input?"); PlanCompiler.Assert(((VarDefOp)n.Child0.Op).Var == op.Var, "Un-nest var not found?"); PlanCompiler.Assert(n.Child0.HasChild0, "VarDef without input?"); var newNode = n.Child0.Child0; if (OpType.Function == newNode.Op.OpType) { // If we have an unnest over a function, there's nothing more we can do // This really means that the underlying store has the ability to // support TVFs, and therefore unnests, and we simply leave it as is return n; } else if (OpType.Collect == newNode.Op.OpType) { // UnnestOp(VarDef(CollectOp(PhysicalProjectOp(x)))) ==> x PlanCompiler.Assert(newNode.HasChild0, "collect without input?"); newNode = newNode.Child0; PlanCompiler.Assert(newNode.Op.OpType == OpType.PhysicalProject, "collect without physicalProject?"); // Ensure others that reference my var will know to use me; m_definingNodeMap.Add(op.Var, newNode); } else if (OpType.VarRef == newNode.Op.OpType) { // UnnestOp(VarDef(VarRef(v))) ==> copy-of-defining-node-for-v // // The Unnest's input is a VarRef; we need to replace it with // the defining node, and ensure we fixup the vars. var refVar = ((VarRefOp)newNode.Op).Var; Node refVarDefiningNode; var found = m_definingNodeMap.TryGetValue(refVar, out refVarDefiningNode); PlanCompiler.Assert(found, "Could not find a definition for a referenced collection var"); newNode = CopyCollectionVarDefinition(refVarDefiningNode); PlanCompiler.Assert(newNode.Op.OpType == OpType.PhysicalProject, "driving node is not physicalProject?"); } else { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.InvalidInternalTree, 2, newNode.Op.OpType); } IEnumerable<Var> inputVars = ((PhysicalProjectOp)newNode.Op).Outputs; PlanCompiler.Assert(newNode.HasChild0, "physicalProject without input?"); newNode = newNode.Child0; // Dev10 #530752 : it is not correct to just remove the sort key if (newNode.Op.OpType == OpType.Sort) { m_foundSortUnderUnnest = true; } // Update the replacement vars to reflect the pulled up operation UpdateReplacementVarMap(op.Table.Columns, inputVars); #if DEBUG var size = input.Length; // GC.KeepAlive makes FxCop Grumpy. var output = Dump.ToXml(newNode); #endif //DEBUG return newNode; }
// <summary> // Clone an UnnestOp // </summary> // <param name="op"> The Op to Copy </param> // <param name="n"> The Node that references the Op </param> // <returns> A copy of the original Node that references a copy of the original Op </returns> public override Node Visit(UnnestOp op, Node n) { // Visit the Node's children and map their Vars var children = ProcessChildren(n); // Get the mapped unnest-var var mappedVar = GetMappedVar(op.Var); // Create a new unnestOp var newTable = m_destCmd.CreateTableInstance(op.Table.TableMetadata); var newUnnest = m_destCmd.CreateUnnestOp(mappedVar, newTable); // Map the corresponding tables/columns MapTable(newUnnest.Table, op.Table); // create the unnest node return m_destCmd.CreateNode(newUnnest, children); }
/// <summary> /// UnnestOp handling /// </summary> /// <param name="op"></param> /// <param name="n"></param> public override void Visit(UnnestOp op, Node n) { VisitChildren(n); }
/// <summary> /// UnnestOp handling /// </summary> /// <param name="op"> </param> /// <param name="n"> </param> public override void Visit(UnnestOp op, Node n) { VisitChildren(n); }