public override void Visit(IsOfOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { PropertyRefList propertyRefs = new PropertyRefList(); propertyRefs.Add((PropertyRef)TypeIdPropertyRef.Instance); this.AddPropertyRefs(n.Child0, propertyRefs); this.VisitChildren(n); }
/// <summary> /// IsOfOp handling /// /// Simply requests the "typeid" property from /// the input. No other property is required /// </summary> /// <param name="op">IsOf op</param> /// <param name="n">Node to visit</param> public override void Visit(IsOfOp op, Node n) { // The only property I need from my child is the typeid property; PropertyRefList childProps = new PropertyRefList(); childProps.Add(TypeIdPropertyRef.Instance); AddPropertyRefs(n.Child0, childProps); VisitChildren(n); }
/// <summary> /// Clone an IsOfOp /// </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(IsOfOp op, Node n) { if (op.IsOfOnly) { return(CopyDefault(m_destCmd.CreateIsOfOnlyOp(op.IsOfType), n)); } else { return(CopyDefault(m_destCmd.CreateIsOfOp(op.IsOfType), n)); } }
public override void Visit(IsOfOp op, Node n) { using (new AutoXml(this, (op.IsOfOnly ? "IsOfOnly" : "IsOf"))) { string separator = string.Empty; foreach (Node chi in n.Children) { WriteString(separator); VisitNode(chi); separator = ","; } } }
/// <summary> /// IsOf /// Convert an IsOf operator into a typeid comparison: /// IsOfOnly(e, T) => e.TypeId == TypeIdValue(T) /// IsOf(e, T) => e.TypeId like TypeIdValue(T)% escape null /// </summary> /// <param name="op"> The IsOfOp to handle </param> /// <param name="n"> current isof subtree </param> /// <returns> new subtree </returns> public override Node Visit(IsOfOp op, Node n) { // First visit all my children VisitChildren(n); if (!TypeUtils.IsStructuredType(op.IsOfType)) { return n; } var typeInfo = m_typeInfo.GetTypeInfo(op.IsOfType); var newNode = CreateTypeComparisonOp(n.Child0, typeInfo, op.IsOfOnly); return newNode; }
private Node ExpandView(ScanTableOp scanTableOp, ref IsOfOp typeFilter) { var entitySet = scanTableOp.Table.TableMetadata.Extent; PlanCompiler.Assert(entitySet != null, "The target of a ScanTableOp must reference an EntitySet to be used with ExpandView"); PlanCompiler.Assert( entitySet.EntityContainer.DataSpace == DataSpace.CSpace, "Store entity sets cannot have Query Mapping Views and should not be used with ExpandView"); if (typeFilter != null && !typeFilter.IsOfOnly && TypeSemantics.IsSubTypeOf(entitySet.ElementType, typeFilter.IsOfType.EdmType)) { // // If a type filter is being applied to the ScanTableOp, but that filter is asking // for all elements that are the same type or a supertype of the element type of the // target entity set, then the type filter is a no-op and can safely be discarded - // IF AND ONLY IF the type filter is 'OfType' - which includes subtypes - and NOT // 'IsOfOnly' - which requires an exact type match, and so does not include subtypes. // typeFilter = null; } // // Call the GetGeneratedView method to retrieve the query mapping view for the extent referenced // by the ScanTableOp. The actual method used to do this differs depending on whether the default // Query Mapping View is sufficient or a targeted view that only filters by element type is required. // GeneratedView definingQuery = null; var requiredType = scanTableOp.Table.TableMetadata.Extent.ElementType; var includeSubtypes = true; if (typeFilter != null) { // // A type filter is being applied to the ScanTableOp; it may be possible to produce // an optimized expansion of the view based on type-specific views generated for the // C-Space entity set. // The type for which the view should be tuned is the 'OfType' specified on the type filter. // If the type filter is an 'IsOfOnly' filter then the view should NOT include subtypes of the required type. // requiredType = (EntityTypeBase)typeFilter.IsOfType.EdmType; includeSubtypes = !typeFilter.IsOfOnly; if (m_command.MetadataWorkspace.TryGetGeneratedViewOfType(entitySet, requiredType, includeSubtypes, out definingQuery)) { // // At this point a type-specific view was found that satisifies the type filter's // constraints in terms of required type and whether subtypes should be included; // the type filter itself is now unnecessary and should be set to null indicating // that it can be safely removed (see ProcessScanTableOp and Visit(FilterOp) for this). // typeFilter = null; } } // // If a generated view has not been obtained at this point then either: // - A type filter was specified but no type-specific view exists that satisfies its constraints. // OR // - No type filter was specified. // In either case the default query mapping view for the referenced entity set should now be retrieved. // if (null == definingQuery) { definingQuery = m_command.MetadataWorkspace.GetGeneratedView(entitySet); } // // If even the default query mapping view was not found then we cannot continue. // This implies that the set was not mapped, which should not be allowed, therefore // a retail assert is used here instead of a regular exception. // PlanCompiler.Assert(definingQuery != null, Strings.ADP_NoQueryMappingView(entitySet.EntityContainer.Name, entitySet.Name)); // // At this point we're guaranteed to have found a defining query for the view. // We're now going to convert this into an IQT, and then copy it into our own IQT. // var ret = definingQuery.GetInternalTree(m_command); // // Make sure we're tracking what we've asked any discriminator maps to contain. // DetermineDiscriminatorMapUsage(ret, entitySet, requiredType, includeSubtypes); // // Build up a ScanViewOp to "cap" the defining query below // var scanViewOp = m_command.CreateScanViewOp(scanTableOp.Table); ret = m_command.CreateNode(scanViewOp, ret); return ret; }
/// <summary> /// Checks to see if this filterOp represents an IS OF (or IS OF ONLY) filter over a ScanTableOp /// </summary> /// <param name="n">the filterOp node</param> /// <param name="ofType">(OUT) the Type to restrict to</param> /// <param name="isOfOnly">(OUT) was an ONLY clause specified</param> /// <returns></returns> private static bool IsOfTypeOverScanTable(Node n, out IsOfOp typeFilter) { typeFilter = null; // // Is the predicate an IsOf predicate // var isOfOp = n.Child1.Op as IsOfOp; if (isOfOp == null) { return false; } // // Is the Input RelOp a ScanTableOp // var scanTableOp = n.Child0.Op as ScanTableOp; if (scanTableOp == null || scanTableOp.Table.Columns.Count != 1) { return false; } // // Is the argument to the IsOfOp the single column of the table? // var varRefOp = n.Child1.Child0.Op as VarRefOp; if (varRefOp == null || varRefOp.Var != scanTableOp.Table.Columns[0]) { return false; } // // All conditions match. Return the info from the IsOf predicate // typeFilter = isOfOp; return true; }
private Node ProcessScanTable(Node scanTableNode, ScanTableOp scanTableOp, ref IsOfOp typeFilter) { HandleTableOpMetadata(scanTableOp); PlanCompiler.Assert(scanTableOp.Table.TableMetadata.Extent != null, "ScanTableOp must reference a table with an extent"); Node ret = null; // // Get simple things out of the way. If we're dealing with an S-space entityset, // simply return the node // if (scanTableOp.Table.TableMetadata.Extent.EntityContainer.DataSpace == DataSpace.SSpace) { return scanTableNode; } else { // "Expand" the C-Space view ret = ExpandView(scanTableOp, ref typeFilter); } // Rerun the processor over the resulting subtree ret = VisitNode(ret); return ret; }
// Translates // 'R is of T' // to // '(case when not (R is null) then True else null end) = True' // // Input requirements: // // - IsOfOp and argument to same must be in the same hierarchy. // - IsOfOp and argument must have the same type // - IsOfOp.IsOfType may not have super- or sub- types (validate // using CanRewriteTypeTest) // // Design requirements: // // - Must return true if the record exists // - Must return null if it does not // - Must be in predicate form to avoid confusing SQL gen // // The translation assumes R is of T when R is non null. private Node RewriteIsOfAsIsNull(IsOfOp op, Node n) { // construct 'R is null' predicate var isNullOp = m_command.CreateConditionalOp(OpType.IsNull); var isNullNode = m_command.CreateNode(isNullOp, n.Child0); // Process the IsNull node to make sure a null sentinel gets added if needed ProcessConditionalOp(isNullOp, isNullNode); // construct 'not (R is null)' predicate var notOp = m_command.CreateConditionalOp(OpType.Not); var notNode = m_command.CreateNode(notOp, isNullNode); // construct 'True' result var trueOp = m_command.CreateConstantOp(op.Type, true); var trueNode = m_command.CreateNode(trueOp); // construct 'null' default result var nullOp = m_command.CreateNullOp(op.Type); var nullNode = m_command.CreateNode(nullOp); // create case statement var caseOp = m_command.CreateCaseOp(op.Type); var caseNode = m_command.CreateNode(caseOp, notNode, trueNode, nullNode); // create 'case = true' operator var equalsOp = m_command.CreateComparisonOp(OpType.EQ); var equalsNode = m_command.CreateNode(equalsOp, caseNode, trueNode); return equalsNode; }
/// <summary> /// Handler for an IsOfOp. /// Keeps track of the IsOfType (if it is a structured type) and rewrites the /// operator if the argument is guaranteed to be of type op.IsOfType /// </summary> /// <param name="op">Current IsOfOp</param> /// <param name="n">Current subtree</param> /// <returns>Current subtree</returns> public override Node Visit(IsOfOp op, Node n) { VisitScalarOpDefault(op, n); // default handling first // keep track of any structured types AddTypeReference(op.IsOfType); // See if the IsOfOp can be rewritten (if it's not polymorphic) if (CanRewriteTypeTest(op.IsOfType.EdmType, n.Child0.Op.Type.EdmType)) { n = RewriteIsOfAsIsNull(op, n); } // For IsOfOnly(abstract type), suppress DiscriminatorMaps since no explicit type id is available for // abstract types. if (op.IsOfOnly && op.IsOfType.EdmType.Abstract) { m_suppressDiscriminatorMaps = true; } return n; }
/// <summary> /// Visitor pattern method for IsOp /// </summary> /// <param name="op"> The IsOp being visited </param> /// <param name="n"> The Node that references the Op </param> public virtual void Visit(IsOfOp op, Node n) { VisitScalarOpDefault(op, n); }
/// <summary> /// IsOfOp handling /// /// Simply requests the "typeid" property from /// the input. No other property is required /// </summary> /// <param name="op"> IsOf op </param> /// <param name="n"> Node to visit </param> public override void Visit(IsOfOp op, Node n) { // The only property I need from my child is the typeid property; var childProps = new PropertyRefList(); childProps.Add(TypeIdPropertyRef.Instance); AddPropertyRefs(n.Child0, childProps); VisitChildren(n); }
// <summary> // Clone an IsOfOp // </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(IsOfOp op, Node n) { if (op.IsOfOnly) { return CopyDefault(m_destCmd.CreateIsOfOnlyOp(op.IsOfType), n); } else { return CopyDefault(m_destCmd.CreateIsOfOp(op.IsOfType), n); } }