internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember) { DbExpression cqt = null; AsCql( // createRef action (refScopeEntitySet, keyMemberOutputPaths) => { // Construct a scoped reference: CreateRef(CPerson1Set, NewRow(pid1, pid2), CPerson1) EntityType refEntityType = (EntityType)(((RefType)outputMember.EdmType).ElementType); cqt = refScopeEntitySet.CreateRef( refEntityType, keyMemberOutputPaths.Select(km => row.Property(km.CqlFieldAlias))); }, // createType action (membersOutputPaths) => { // Construct an entity/complex/Association type in the Members order for fields: CPerson(CPerson1_Pid, CPerson1_Name) cqt = TypeUsage.Create(m_edmType).New( membersOutputPaths.Select(m => row.Property(m.CqlFieldAlias))); }, outputMember); return(cqt); }
internal DbExpression FindInput(DbExpression row) { DbExpression instance = row; for (int index = this.m_parentQualifiers.Count - 1; index >= this.m_indexInParentQualifiers; --index) { instance = (DbExpression)instance.Property(this.m_parentQualifiers[index]); } return((DbExpression)instance.Property(this.m_leafQualifier)); }
internal DbExpression FindInput(DbExpression row) { DbExpression cqt = row; for (int i = m_parentQualifiers.Count - 1; i >= m_indexInParentQualifiers; --i) { cqt = cqt.Property(m_parentQualifiers[i]); } return(cqt.Property(m_leafQualifier)); }
internal override ObjectSpanRewriter.SpanTrackingInfo CreateEntitySpanTrackingInfo( DbExpression expression, EntityType entityType) { ObjectSpanRewriter.SpanTrackingInfo spanTrackingInfo = new ObjectSpanRewriter.SpanTrackingInfo(); ObjectFullSpanRewriter.SpanPathInfo spanPathInfo = this._currentSpanPath.Peek(); if (spanPathInfo.Children != null) { int index = 1; foreach (KeyValuePair <NavigationProperty, ObjectFullSpanRewriter.SpanPathInfo> child in spanPathInfo.Children) { if (spanTrackingInfo.ColumnDefinitions == null) { spanTrackingInfo = this.InitializeTrackingInfo(this.RelationshipSpan); } DbExpression expression1 = (DbExpression)expression.Property(child.Key); this._currentSpanPath.Push(child.Value); DbExpression dbExpression = this.Rewrite(expression1); this._currentSpanPath.Pop(); spanTrackingInfo.ColumnDefinitions.Add(new KeyValuePair <string, DbExpression>(spanTrackingInfo.ColumnNames.Next(), dbExpression)); AssociationEndMember propertyTargetEnd = this.GetNavigationPropertyTargetEnd(child.Key); spanTrackingInfo.SpannedColumns[index] = propertyTargetEnd; if (this.RelationshipSpan) { spanTrackingInfo.FullSpannedEnds[propertyTargetEnd] = true; } ++index; } } return(spanTrackingInfo); }
private static DbExpression GenerateColumnRef(DbExpression row, EdmProperty column) { Debug.Assert(row.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RowType, "Input type is expected to be a row type."); var rowType = (RowType)row.ResultType.EdmType; Debug.Assert(rowType.Properties.Contains(column.Name), "Column name must be resolvable in the TVF result type."); return(row.Property(column.Name)); }
internal override SpanTrackingInfo CreateEntitySpanTrackingInfo(DbExpression expression, EntityType entityType) { var tracking = new SpanTrackingInfo(); var currentInfo = _currentSpanPath.Peek(); if (currentInfo.Children != null) { // The current SpanPathInfo instance on the top of the span path stack indicates // which navigation properties should be retrieved from this Entity-typed expression // and also specifies (in the form of child SpanPathInfo instances) which sub-paths // must be expanded for each of those navigation properties. // The SpanPathInfo instance may be the root instance or a SpanPathInfo that represents a sub-path. var idx = 1; // SpanRoot is always the first (zeroth) column, full- and relationship-span columns follow. foreach (var nextInfo in currentInfo.Children) { // If the tracking information was not initialized yet, do so now. if (null == tracking.ColumnDefinitions) { tracking = InitializeTrackingInfo(RelationshipSpan); } // Create a property expression that retrieves the specified navigation property from the Entity-typed expression. // Note that the expression is cloned since it may be used as the instance of multiple property expressions. DbExpression columnDef = expression.Property(nextInfo.Key); // Rewrite the result of the navigation property. This is required for two reasons: // 1. To continue spanning the current Include path. // 2. To apply relationship span to the Entity or EntityCollection produced by the navigation property, if necessary. // Consider an Include path of "Order" for a query that returns OrderLines - the Include'd Orders should have // their associated Customer relationship spanned. // Note that this will recursively call this method with the Entity type of the result of the // navigation property, which will in turn call loop through the sub-paths of this navigation // property and adjust the stack to track which Include path is being expanded and which // element of that path is considered 'current'. _currentSpanPath.Push(nextInfo.Value); columnDef = Rewrite(columnDef); _currentSpanPath.Pop(); // Add a new column to the tracked columns using the rewritten column definition tracking.ColumnDefinitions.Add(new KeyValuePair <string, DbExpression>(tracking.ColumnNames.Next(), columnDef)); var targetEnd = GetNavigationPropertyTargetEnd(nextInfo.Key); tracking.SpannedColumns[idx] = targetEnd; // If full span and relationship span are both required, a relationship span may be rendered // redundant by an already added full span. Therefore the association ends that have been expanded // as part of full span are tracked using a dictionary. if (RelationshipSpan) { tracking.FullSpannedEnds[targetEnd] = true; } idx++; } } return(tracking); }
// <summary> // Rebuild the current scope entry expression as the property chain off the <paramref name="parentVarRef" /> expression. // Also build // - <see cref="IGroupExpressionExtendedInfo.GroupVarBasedExpression" /> off the <paramref name="parentGroupVarRef" /> expression; // - <see cref="IGroupExpressionExtendedInfo.GroupAggBasedExpression" /> off the <paramref name="groupAggRef" /> expression. // This adjustment is reversable by <see cref="RollbackAdjustmentToGroupVar" />(...). // </summary> internal void AdjustToGroupVar( DbVariableReferenceExpression parentVarRef, DbVariableReferenceExpression parentGroupVarRef, DbVariableReferenceExpression groupAggRef) { // Adjustment is not reentrant. Debug.Assert(_groupVarBasedExpression == null, "_groupVarBasedExpression == null"); Debug.Assert(_groupAggBasedExpression == null, "_groupAggBasedExpression == null"); // // Let's assume this entry represents variable "x" in the following query: // select x, y, z from {1, 2} as x join {2, 3} as y on x = y join {3, 4} as z on y = z // In this case _propRefs contains x._##join0._##join1 and the corresponding input expression looks like this: // |_Input : '_##join1' // | |_InnerJoin // | |_Left : '_##join0' // | | |_InnerJoin // | | |_Left : 'x' // | | |_Right : 'y' // | |_Right : 'z' // When we start processing a group by, like in this query: // select k1, k2, k3 from {1, 2} as x join {2, 3} as y on x = y join {3, 4} as z on y = z group by x as k1, y as k2, z as k3 // we are switching to the following input expression: // |_Input : '_##geb2', '_##group3' // | |_InnerJoin // | |_Left : '_##join0' // | | |_InnerJoin // | | |_Left : 'x' // | | |_Right : 'y' // | |_Right : 'z' // where _##join1 is replaced by _##geb2 for the regular expression and by _##group3 for the group var based expression. // So the switch, or the adjustment, is done by // a. replacing _##join1 with _##geb2 in _propRefs and rebuilding the regular expression accordingly to get // the following property chain: _##geb2._##join1.x // b. building a group var based expression using _##group3 instead of _##geb2 to get // the following property chain: _##group3._##join1.x // // // Rebuild ScopeEntry.Expression using the new parent var. // ReplaceParentVar(parentVarRef); // // Build the GroupVarBasedExpression and GroupAggBasedExpression, // take into account that parentVarRef has already been added to the _propRefs in the AdjustToParentVar(...) call, so ignore it. // _groupVarBasedExpression = parentGroupVarRef; _groupAggBasedExpression = groupAggRef; if (_propRefs != null) { for (var i = _propRefs.Count - 2 /*ignore the parentVarRef*/; i >= 0; --i) { _groupVarBasedExpression = _groupVarBasedExpression.Property(_propRefs[i]); _groupAggBasedExpression = _groupAggBasedExpression.Property(_propRefs[i]); } } }
private void FlattenProperties( DbExpression input, IList <DbPropertyExpression> flattenedProperties) { foreach (EdmProperty property in input.ResultType.GetProperties()) { DbPropertyExpression propertyExpression = input.Property(property); if (BuiltInTypeKind.PrimitiveType == property.TypeUsage.EdmType.BuiltInTypeKind) { flattenedProperties.Add(propertyExpression); } else { this.FlattenProperties((DbExpression)propertyExpression, flattenedProperties); } } }
/// <summary> /// Adds the flattened properties on the input to the flattenedProperties list. /// </summary> /// <param name="input"></param> /// <param name="flattenedProperties"></param> private void FlattenProperties(DbExpression input, IList <DbPropertyExpression> flattenedProperties) { IList <EdmProperty> properties = TypeHelpers.GetProperties(input.ResultType); Debug.Assert(properties.Count != 0, "No nested properties when FlattenProperties called?"); for (int i = 0; i < properties.Count; i++) { DbExpression propertyInput = input; DbPropertyExpression propertyExpression = propertyInput.Property(properties[i]); if (TypeSemantics.IsPrimitiveType(properties[i].TypeUsage)) { flattenedProperties.Add(propertyExpression); } else { Debug.Assert(TypeSemantics.IsEntityType(properties[i].TypeUsage) || TypeSemantics.IsRowType(properties[i].TypeUsage), "The input to FlattenProperties is not of EntityType or RowType?"); FlattenProperties(propertyExpression, flattenedProperties); } } }
// <summary> // Prepend <paramref name="parentVarRef" /> to the property chain. // </summary> internal SourceScopeEntry AddParentVar(DbVariableReferenceExpression parentVarRef) { // // No parent var adjustment is allowed while adjusted to group var (see AdjustToGroupVar(...) for more info). // Debug.Assert(_groupVarBasedExpression == null, "_groupVarBasedExpression == null"); Debug.Assert(_groupAggBasedExpression == null, "_groupAggBasedExpression == null"); if (_propRefs == null) { Debug.Assert(_varBasedExpression is DbVariableReferenceExpression, "_varBasedExpression is DbVariableReferenceExpression"); _propRefs = new List <string>(2); _propRefs.Add(((DbVariableReferenceExpression)_varBasedExpression).VariableName); } _varBasedExpression = parentVarRef; for (var i = _propRefs.Count - 1; i >= 0; --i) { _varBasedExpression = _varBasedExpression.Property(_propRefs[i]); } _propRefs.Add(parentVarRef.VariableName); return(this); }
/// <summary> /// Prepend <paramref name="parentVarRef" /> to the property chain. /// </summary> internal SourceScopeEntry AddParentVar(DbVariableReferenceExpression parentVarRef) { // // No parent var adjustment is allowed while adjusted to group var (see AdjustToGroupVar(...) for more info). // Debug.Assert(_groupVarBasedExpression == null, "_groupVarBasedExpression == null"); Debug.Assert(_groupAggBasedExpression == null, "_groupAggBasedExpression == null"); if (_propRefs == null) { Debug.Assert(_varBasedExpression is DbVariableReferenceExpression, "_varBasedExpression is DbVariableReferenceExpression"); _propRefs = new List<string>(2); _propRefs.Add(((DbVariableReferenceExpression)_varBasedExpression).VariableName); } _varBasedExpression = parentVarRef; for (var i = _propRefs.Count - 1; i >= 0; --i) { _varBasedExpression = _varBasedExpression.Property(_propRefs[i]); } _propRefs.Add(parentVarRef.VariableName); return this; }
internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull) { // Get e.g., row._from1 return(row.Property(SlotName)); }
internal DbRelatedEntityRef AsCqt(DbExpression row) { return(DbExpressionBuilder.CreateRelatedEntityRef(this.m_fromEnd, this.m_toEnd, (DbExpression)this.m_toEndEntitySet.CreateRef(this.m_toEndEntityType, (IEnumerable <DbExpression>) this.m_toEndEntityKeyMemberPaths.Select <MemberPath, DbPropertyExpression>((Func <MemberPath, DbPropertyExpression>)(keyMember => row.Property(keyMember.CqlFieldAlias)))))); }
internal DbExpression AsCqt(DbExpression row) { this.AsCql((Action <string>)(memberName => row = (DbExpression)row.Property(memberName)), (Action)(() => row = (DbExpression)row.GetRefKey()), (Action <StructuralType>)(treatAsType => row = (DbExpression)row.TreatAs(TypeUsage.Create((EdmType)treatAsType)))); return(row); }
private DbExpression RecursivelyRewriteEqualsExpression(DbExpression left, DbExpression right, EqualsPattern pattern) { // check if either side is an initializer type RowType leftType = left.ResultType.EdmType as RowType; RowType rightType = left.ResultType.EdmType as RowType; if (null != leftType || null != rightType) { if ((null != leftType && null != rightType) && leftType.EdmEquals(rightType)) { DbExpression shreddedEquals = null; // if the types are the same, use struct equivalence semantics foreach (EdmProperty property in leftType.Properties) { DbPropertyExpression leftElement = left.Property(property); DbPropertyExpression rightElement = right.Property(property); DbExpression elementsEquals = RecursivelyRewriteEqualsExpression( leftElement, rightElement, pattern); // build up and expression if (null == shreddedEquals) { shreddedEquals = elementsEquals; } else { shreddedEquals = shreddedEquals.And(elementsEquals); } } return shreddedEquals; } else { // if one or both sides is an initializer and the types are not the same, // "equals" always evaluates to false return DbExpressionBuilder.False; } } else { return ImplementEquality(left, right, pattern); } }
internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember) { DbExpression cqt = null; AsCql( // createRef action (refScopeEntitySet, keyMemberOutputPaths) => { // Construct a scoped reference: CreateRef(CPerson1Set, NewRow(pid1, pid2), CPerson1) EntityType refEntityType = (EntityType)(((RefType)outputMember.EdmType).ElementType); cqt = refScopeEntitySet.CreateRef( refEntityType, keyMemberOutputPaths.Select(km => row.Property(km.CqlFieldAlias))); }, // createType action (membersOutputPaths) => { // Construct an entity/complex/Association type in the Members order for fields: CPerson(CPerson1_Pid, CPerson1_Name) cqt = TypeUsage.Create(m_edmType).New( membersOutputPaths.Select(m => row.Property(m.CqlFieldAlias))); }, outputMember); return cqt; }
/// <summary> /// Rebuild the current scope entry expression as the property chain off the <paramref name="parentVarRef" /> expression. /// Also build /// - <see cref="IGroupExpressionExtendedInfo.GroupVarBasedExpression" /> off the <paramref name="parentGroupVarRef" /> expression; /// - <see cref="IGroupExpressionExtendedInfo.GroupAggBasedExpression" /> off the <paramref name="groupAggRef" /> expression. /// This adjustment is reversable by <see cref="RollbackAdjustmentToGroupVar" />(...). /// </summary> internal void AdjustToGroupVar( DbVariableReferenceExpression parentVarRef, DbVariableReferenceExpression parentGroupVarRef, DbVariableReferenceExpression groupAggRef) { // Adjustment is not reentrant. Debug.Assert(_groupVarBasedExpression == null, "_groupVarBasedExpression == null"); Debug.Assert(_groupAggBasedExpression == null, "_groupAggBasedExpression == null"); // // Let's assume this entry represents variable "x" in the following query: // select x, y, z from {1, 2} as x join {2, 3} as y on x = y join {3, 4} as z on y = z // In this case _propRefs contains x._##join0._##join1 and the corresponding input expression looks like this: // |_Input : '_##join1' // | |_InnerJoin // | |_Left : '_##join0' // | | |_InnerJoin // | | |_Left : 'x' // | | |_Right : 'y' // | |_Right : 'z' // When we start processing a group by, like in this query: // select k1, k2, k3 from {1, 2} as x join {2, 3} as y on x = y join {3, 4} as z on y = z group by x as k1, y as k2, z as k3 // we are switching to the following input expression: // |_Input : '_##geb2', '_##group3' // | |_InnerJoin // | |_Left : '_##join0' // | | |_InnerJoin // | | |_Left : 'x' // | | |_Right : 'y' // | |_Right : 'z' // where _##join1 is replaced by _##geb2 for the regular expression and by _##group3 for the group var based expression. // So the switch, or the adjustment, is done by // a. replacing _##join1 with _##geb2 in _propRefs and rebuilding the regular expression accordingly to get // the following property chain: _##geb2._##join1.x // b. building a group var based expression using _##group3 instead of _##geb2 to get // the following property chain: _##group3._##join1.x // // // Rebuild ScopeEntry.Expression using the new parent var. // ReplaceParentVar(parentVarRef); // // Build the GroupVarBasedExpression and GroupAggBasedExpression, // take into account that parentVarRef has already been added to the _propRefs in the AdjustToParentVar(...) call, so ignore it. // _groupVarBasedExpression = parentGroupVarRef; _groupAggBasedExpression = groupAggRef; if (_propRefs != null) { for (var i = _propRefs.Count - 2 /*ignore the parentVarRef*/; i >= 0; --i) { _groupVarBasedExpression = _groupVarBasedExpression.Property(_propRefs[i]); _groupAggBasedExpression = _groupAggBasedExpression.Property(_propRefs[i]); } } }
internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull) { return((DbExpression)row.Property(this.SlotName)); }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression lambdaExpression = expression as DbLambdaExpression; DbNewInstanceExpression newRow; if (lambdaExpression != null) { // NOTE: We rely on the fact that today span cannot be done over queries containing DbLambdaExpressions // created by users, because user-created expressions cannot be used for querying in O-space. // If that were to change, pushing span beyond a LambdaExpression could cause variable name // collisions between the variable names used in the Lambda and the names generated by the // RelationshipNavigationVisitor. newRow = lambdaExpression.Lambda.Body as DbNewInstanceExpression; } else { newRow = expression as DbNewInstanceExpression; } Dictionary<int, DbExpression> unmodifiedColumns = null; Dictionary<int, DbExpression> spannedColumns = null; for(int idx = 0; idx < rowType.Properties.Count; idx++) { // Retrieve the property that represents the current column EdmProperty columnProp = rowType.Properties[idx]; // Construct an expression that defines the current column. DbExpression columnExpr = null; if(newRow != null) { // For a row-constructing NewInstance expression, the corresponding argument can simply be used columnExpr = newRow.Arguments[idx]; } else { // For all other expressions the property corresponding to the column name must be retrieved // from the row-typed expression columnExpr = expression.Property(columnProp.Name); } DbExpression spannedColumn = this.Rewrite(columnExpr); if (!object.ReferenceEquals(spannedColumn, columnExpr)) { // If so, then update the dictionary of column index to span information if (null == spannedColumns) { spannedColumns = new Dictionary<int, DbExpression>(); } spannedColumns[idx] = spannedColumn; } else { // Otherwise, update the dictionary of column index to unmodified expression if(null == unmodifiedColumns) { unmodifiedColumns = new Dictionary<int, DbExpression>(); } unmodifiedColumns[idx] = columnExpr; } } // A new expression need only be built if at least one column was spanned if(null == spannedColumns) { // No columns were spanned, indicate that the original expression should remain. return expression; } else { // At least one column was spanned, so build a new row constructor that defines the new row, including spanned columns. List<DbExpression> columnArguments = new List<DbExpression>(rowType.Properties.Count); List<EdmProperty> properties = new List<EdmProperty>(rowType.Properties.Count); for (int idx = 0; idx < rowType.Properties.Count; idx++) { EdmProperty columnProp = rowType.Properties[idx]; DbExpression columnDef = null; if (!spannedColumns.TryGetValue(idx, out columnDef)) { columnDef = unmodifiedColumns[idx]; } columnArguments.Add(columnDef); properties.Add(new EdmProperty(columnProp.Name, columnDef.ResultType)); } // Copy over any eLinq initializer metadata (if present, or null if not). // Note that this initializer metadata does not strictly match the new row type // that includes spanned columns, but will be correct once the object materializer // has interpreted the query results to produce the correct value for each colum. RowType rewrittenRow = new RowType(properties, rowType.InitializerMetadata); TypeUsage rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow); DbExpression rewritten = rewrittenRowTypeUsage.New(columnArguments); // SQLBUDT #554182: If we insert a new projection we should should make sure to // not interfere with the nullability of the input. // In particular, if the input row is null and we construct a new row as a projection over its columns // we would get a row consisting of nulls, instead of a null row. // Thus, given an input X, we rewritte it as: if (X is null) then NULL else rewritten. if (newRow == null) { DbExpression condition = DbExpressionBuilder.CreateIsNullExpressionAllowingRowTypeArgument(expression); DbExpression nullExpression = DbExpressionBuilder.Null(rewrittenRowTypeUsage); rewritten = DbExpressionBuilder.Case( new List<DbExpression>(new DbExpression[] { condition }), new List<DbExpression>(new DbExpression[] { nullExpression }), rewritten); } // Add an entry to the spanned row type => original row type map for the new row type. AddSpannedRowType(rewrittenRow, expression.ResultType); if (lambdaExpression != null && newRow != null) { rewritten = DbLambda.Create(rewritten, lambdaExpression.Lambda.Variables).Invoke(lambdaExpression.Arguments); } return rewritten; } }
internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember) { DbExpression cqt = (DbExpression)null; this.AsCql((Action <EntitySet, IList <MemberPath> >)((refScopeEntitySet, keyMemberOutputPaths) => { EntityType elementType = (EntityType)((RefType)outputMember.EdmType).ElementType; cqt = (DbExpression)refScopeEntitySet.CreateRef(elementType, (IEnumerable <DbExpression>)keyMemberOutputPaths.Select <MemberPath, DbPropertyExpression>((Func <MemberPath, DbPropertyExpression>)(km => row.Property(km.CqlFieldAlias)))); }), (Action <IList <MemberPath> >)(membersOutputPaths => cqt = (DbExpression)TypeUsage.Create(this.m_edmType).New((IEnumerable <DbExpression>)membersOutputPaths.Select <MemberPath, DbPropertyExpression>((Func <MemberPath, DbPropertyExpression>)(m => row.Property(m.CqlFieldAlias))))), outputMember); return(cqt); }
// effects: unwraps any "structured" set sources such as IGrouping instances // (which acts as both a set and a structure containing a property) private DbExpression NormalizeSetSource(DbExpression input) { DebugCheck.NotNull(input); // If input looks like "select x from (...) as x", rewrite it as "(...)". // If input has span information attached to to it then leave it as is, otherwise // span info will be lost. Span span; if (input.ExpressionKind == DbExpressionKind.Project && !TryGetSpan(input, out span)) { var project = (DbProjectExpression)input; if (project.Projection == project.Input.Variable) { input = project.Input.Expression; } } // determine if the lambda input is an IGrouping or EntityCollection that needs to be unwrapped InitializerMetadata initializerMetadata; if (InitializerMetadata.TryGetInitializerMetadata(input.ResultType, out initializerMetadata)) { if (initializerMetadata.Kind == InitializerMetadataKind.Grouping) { // for group by, redirect the binding to the group (rather than the property) input = input.Property(GroupColumnName); } else if (initializerMetadata.Kind == InitializerMetadataKind.EntityCollection) { // for entity collection, redirect the binding to the children input = input.Property(EntityCollectionElementsColumnName); } } return input; }
internal DbRelatedEntityRef AsCqt(DbExpression row) { return DbExpressionBuilder.CreateRelatedEntityRef( m_fromEnd, m_toEnd, m_toEndEntitySet.CreateRef( m_toEndEntityType, m_toEndEntityKeyMemberPaths.Select(keyMember => row.Property(keyMember.CqlFieldAlias)))); }
internal DbRelatedEntityRef AsCqt(DbExpression row) { return(DbExpressionBuilder.CreateRelatedEntityRef( m_fromEnd, m_toEnd, m_toEndEntitySet.CreateRef( m_toEndEntityType, m_toEndEntityKeyMemberPaths.Select(keyMember => row.Property(keyMember.CqlFieldAlias))))); }
private DbExpression GenerateColumnRef(DbExpression row, EdmProperty column) { Debug.Assert(row.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RowType, "Input type is expected to be a row type."); var rowType = (RowType)row.ResultType.EdmType; Debug.Assert(rowType.Properties.Contains(column.Name), "Column name must be resolvable in the TVF result type."); return row.Property(column.Name); }
internal override SpanTrackingInfo CreateEntitySpanTrackingInfo(DbExpression expression, EntityType entityType) { var tracking = new SpanTrackingInfo(); var currentInfo = _currentSpanPath.Peek(); if (currentInfo.Children != null) { // The current SpanPathInfo instance on the top of the span path stack indicates // which navigation properties should be retrieved from this Entity-typed expression // and also specifies (in the form of child SpanPathInfo instances) which sub-paths // must be expanded for each of those navigation properties. // The SpanPathInfo instance may be the root instance or a SpanPathInfo that represents a sub-path. var idx = 1; // SpanRoot is always the first (zeroth) column, full- and relationship-span columns follow. foreach (var nextInfo in currentInfo.Children) { // If the tracking information was not initialized yet, do so now. if (null == tracking.ColumnDefinitions) { tracking = InitializeTrackingInfo(RelationshipSpan); } // Create a property expression that retrieves the specified navigation property from the Entity-typed expression. // Note that the expression is cloned since it may be used as the instance of multiple property expressions. DbExpression columnDef = expression.Property(nextInfo.Key); // Rewrite the result of the navigation property. This is required for two reasons: // 1. To continue spanning the current Include path. // 2. To apply relationship span to the Entity or EntityCollection produced by the navigation property, if necessary. // Consider an Include path of "Order" for a query that returns OrderLines - the Include'd Orders should have // their associated Customer relationship spanned. // Note that this will recursively call this method with the Entity type of the result of the // navigation property, which will in turn call loop through the sub-paths of this navigation // property and adjust the stack to track which Include path is being expanded and which // element of that path is considered 'current'. _currentSpanPath.Push(nextInfo.Value); columnDef = Rewrite(columnDef); _currentSpanPath.Pop(); // Add a new column to the tracked columns using the rewritten column definition tracking.ColumnDefinitions.Add(new KeyValuePair<string, DbExpression>(tracking.ColumnNames.Next(), columnDef)); var targetEnd = GetNavigationPropertyTargetEnd(nextInfo.Key); tracking.SpannedColumns[idx] = targetEnd; // If full span and relationship span are both required, a relationship span may be rendered // redundant by an already added full span. Therefore the association ends that have been expanded // as part of full span are tracked using a dictionary. if (RelationshipSpan) { tracking.FullSpannedEnds[targetEnd] = true; } idx++; } } return tracking; }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression lambdaExpression = expression as DbLambdaExpression; DbNewInstanceExpression instanceExpression = lambdaExpression == null ? expression as DbNewInstanceExpression : lambdaExpression.Lambda.Body as DbNewInstanceExpression; Dictionary <int, DbExpression> dictionary1 = (Dictionary <int, DbExpression>)null; Dictionary <int, DbExpression> dictionary2 = (Dictionary <int, DbExpression>)null; for (int index = 0; index < rowType.Properties.Count; ++index) { EdmProperty property = rowType.Properties[index]; DbExpression expression1 = instanceExpression == null ? (DbExpression)expression.Property(property.Name) : instanceExpression.Arguments[index]; DbExpression dbExpression = this.Rewrite(expression1); if (!object.ReferenceEquals((object)dbExpression, (object)expression1)) { if (dictionary2 == null) { dictionary2 = new Dictionary <int, DbExpression>(); } dictionary2[index] = dbExpression; } else { if (dictionary1 == null) { dictionary1 = new Dictionary <int, DbExpression>(); } dictionary1[index] = expression1; } } if (dictionary2 == null) { return(expression); } List <DbExpression> dbExpressionList = new List <DbExpression>(rowType.Properties.Count); List <EdmProperty> edmPropertyList = new List <EdmProperty>(rowType.Properties.Count); for (int key = 0; key < rowType.Properties.Count; ++key) { EdmProperty property = rowType.Properties[key]; DbExpression dbExpression = (DbExpression)null; if (!dictionary2.TryGetValue(key, out dbExpression)) { dbExpression = dictionary1[key]; } dbExpressionList.Add(dbExpression); edmPropertyList.Add(new EdmProperty(property.Name, dbExpression.ResultType)); } RowType spannedType = new RowType((IEnumerable <EdmProperty>)edmPropertyList, rowType.InitializerMetadata); TypeUsage typeUsage = TypeUsage.Create((EdmType)spannedType); DbExpression dbExpression1 = (DbExpression)typeUsage.New((IEnumerable <DbExpression>)dbExpressionList); if (instanceExpression == null) { dbExpression1 = (DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1] { (DbExpression)expression.IsNull() }), (IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1] { (DbExpression)typeUsage.Null() }), dbExpression1); } this.AddSpannedRowType(spannedType, expression.ResultType); if (lambdaExpression != null && instanceExpression != null) { dbExpression1 = (DbExpression)DbLambda.Create(dbExpression1, (IEnumerable <DbVariableReferenceExpression>)lambdaExpression.Lambda.Variables).Invoke((IEnumerable <DbExpression>)lambdaExpression.Arguments); } return(dbExpression1); }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression lambdaExpression = expression as DbLambdaExpression; DbNewInstanceExpression newRow; if (lambdaExpression != null) { // NOTE: We rely on the fact that today span cannot be done over queries containing DbLambdaExpressions // created by users, because user-created expressions cannot be used for querying in O-space. // If that were to change, pushing span beyond a LambdaExpression could cause variable name // collisions between the variable names used in the Lambda and the names generated by the // RelationshipNavigationVisitor. newRow = lambdaExpression.Lambda.Body as DbNewInstanceExpression; } else { newRow = expression as DbNewInstanceExpression; } Dictionary <int, DbExpression> unmodifiedColumns = null; Dictionary <int, DbExpression> spannedColumns = null; for (int idx = 0; idx < rowType.Properties.Count; idx++) { // Retrieve the property that represents the current column EdmProperty columnProp = rowType.Properties[idx]; // Construct an expression that defines the current column. DbExpression columnExpr = null; if (newRow != null) { // For a row-constructing NewInstance expression, the corresponding argument can simply be used columnExpr = newRow.Arguments[idx]; } else { // For all other expressions the property corresponding to the column name must be retrieved // from the row-typed expression columnExpr = expression.Property(columnProp.Name); } DbExpression spannedColumn = this.Rewrite(columnExpr); if (!object.ReferenceEquals(spannedColumn, columnExpr)) { // If so, then update the dictionary of column index to span information if (null == spannedColumns) { spannedColumns = new Dictionary <int, DbExpression>(); } spannedColumns[idx] = spannedColumn; } else { // Otherwise, update the dictionary of column index to unmodified expression if (null == unmodifiedColumns) { unmodifiedColumns = new Dictionary <int, DbExpression>(); } unmodifiedColumns[idx] = columnExpr; } } // A new expression need only be built if at least one column was spanned if (null == spannedColumns) { // No columns were spanned, indicate that the original expression should remain. return(expression); } else { // At least one column was spanned, so build a new row constructor that defines the new row, including spanned columns. List <DbExpression> columnArguments = new List <DbExpression>(rowType.Properties.Count); List <EdmProperty> properties = new List <EdmProperty>(rowType.Properties.Count); for (int idx = 0; idx < rowType.Properties.Count; idx++) { EdmProperty columnProp = rowType.Properties[idx]; DbExpression columnDef = null; if (!spannedColumns.TryGetValue(idx, out columnDef)) { columnDef = unmodifiedColumns[idx]; } columnArguments.Add(columnDef); properties.Add(new EdmProperty(columnProp.Name, columnDef.ResultType)); } // Copy over any eLinq initializer metadata (if present, or null if not). // Note that this initializer metadata does not strictly match the new row type // that includes spanned columns, but will be correct once the object materializer // has interpreted the query results to produce the correct value for each colum. RowType rewrittenRow = new RowType(properties, rowType.InitializerMetadata); TypeUsage rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow); DbExpression rewritten = rewrittenRowTypeUsage.New(columnArguments); // SQLBUDT #554182: If we insert a new projection we should should make sure to // not interfere with the nullability of the input. // In particular, if the input row is null and we construct a new row as a projection over its columns // we would get a row consisting of nulls, instead of a null row. // Thus, given an input X, we rewritte it as: if (X is null) then NULL else rewritten. if (newRow == null) { DbExpression condition = DbExpressionBuilder.CreateIsNullExpressionAllowingRowTypeArgument(expression); DbExpression nullExpression = DbExpressionBuilder.Null(rewrittenRowTypeUsage); rewritten = DbExpressionBuilder.Case( new List <DbExpression>(new DbExpression[] { condition }), new List <DbExpression>(new DbExpression[] { nullExpression }), rewritten); } // Add an entry to the spanned row type => original row type map for the new row type. AddSpannedRowType(rewrittenRow, expression.ResultType); if (lambdaExpression != null && newRow != null) { rewritten = DbLambda.Create(rewritten, lambdaExpression.Lambda.Variables).Invoke(lambdaExpression.Arguments); } return(rewritten); } }
private DbExpression RecursivelyRewriteEqualsExpression(DbExpression left, DbExpression right, EqualsPattern pattern) { // check if either side is an initializer type var leftType = left.ResultType.EdmType as RowType; var rightType = right.ResultType.EdmType as RowType; if (null != leftType || null != rightType) { if (null != leftType && null != rightType) { DbExpression shreddedEquals = null; // if the types are the same, use struct equivalence semantics foreach (var property in leftType.Properties) { var leftElement = left.Property(property); var rightElement = right.Property(property); var elementsEquals = RecursivelyRewriteEqualsExpression( leftElement, rightElement, pattern); // build up and expression if (null == shreddedEquals) { shreddedEquals = elementsEquals; } else { shreddedEquals = shreddedEquals.And(elementsEquals); } } return shreddedEquals; } else { // if one or both sides is an initializer and the types are not the same, // "equals" always evaluates to false return DbExpressionBuilder.False; } } else { return _funcletizer.RootContext.ContextOptions.UseCSharpNullComparisonBehavior ? ImplementEquality(left, right, EqualsPattern.Store) : ImplementEquality(left, right, pattern); } }
internal override DbExpression AsCqt(DbExpression row, bool skipIsNotNull) { // Get e.g., row._from1 return row.Property(SlotName); }
private static DbExpression GenerateColumnRef(DbExpression row, EdmProperty column) { RowType edmType = (RowType)row.ResultType.EdmType; return((DbExpression)row.Property(column.Name)); }