internal FunctionDefinition(string name, DbLambda lambda, int startPosition, int endPosition) { this._name = name; this._lambda = lambda; this._startPosition = startPosition; this._endPosition = endPosition; }
/// <summary> /// Dumps the specified DbLambda instance /// </summary> /// <param name="lambda">The DbLambda to dump.</param> internal void Dump(DbLambda lambda) { Begin("DbLambda"); Dump(System.Linq.Enumerable.Cast <DbExpression>(lambda.Variables), "Variables", "Variable"); Dump(lambda.Body, "Body"); End("DbLambda"); }
protected virtual DbLambda VisitLambda(DbLambda lambda) { Check.NotNull(lambda, "lambda"); var result = lambda; var newFormals = VisitList( lambda.Variables, varRef => { var newVarType = VisitTypeUsage(varRef.ResultType); if (!ReferenceEquals(varRef.ResultType, newVarType)) { return(CqtBuilder.Variable(newVarType, varRef.VariableName)); } else { return(varRef); } } ); EnterScope(newFormals.ToArray()); // ToArray: Don't pass the List instance directly to OnEnterScope var newBody = VisitExpression(lambda.Body); ExitScope(); if (!ReferenceEquals(lambda.Variables, newFormals) || !ReferenceEquals(lambda.Body, newBody)) { result = CqtBuilder.Lambda(newBody, newFormals); } return(result); }
/// <summary> /// Dumps the specified DbLambda instance /// </summary> /// <param name="lambda"> The DbLambda to dump. </param> internal void Dump(DbLambda lambda) { Begin("DbLambda"); Dump(lambda.Variables.Cast <DbExpression>(), "Variables", "Variable"); Dump(lambda.Body, "Body"); End("DbLambda"); }
protected virtual DbLambda VisitLambda(DbLambda lambda) { EntityUtil.CheckArgumentNull(lambda, "lambda"); DbLambda result = lambda; IList <DbVariableReferenceExpression> newFormals = this.VisitList(lambda.Variables, varRef => { TypeUsage newVarType = this.VisitTypeUsage(varRef.ResultType); if (!object.ReferenceEquals(varRef.ResultType, newVarType)) { return(CqtBuilder.Variable(newVarType, varRef.VariableName)); } else { return(varRef); } } ); this.EnterScope(newFormals.ToArray()); // ToArray: Don't pass the List instance directly to OnEnterScope DbExpression newBody = this.VisitExpression(lambda.Body); this.ExitScope(); if (!object.ReferenceEquals(lambda.Variables, newFormals) || !object.ReferenceEquals(lambda.Body, newBody)) { result = CqtBuilder.Lambda(newBody, newFormals); } return(result); }
/// <summary> /// Compiles eSQL <paramref name="functionDefinition"/> and returns <see cref="DbLambda"/>. /// Guarantees type match of lambda variables and <paramref name="functionParameters"/>. /// Passes thru all excepions coming from <see cref="CqlQuery"/>. /// </summary> static internal DbLambda CompileFunctionDefinition( string functionFullName, string functionDefinition, IList <FunctionParameter> functionParameters, EdmItemCollection edmItemCollection) { Debug.Assert(!String.IsNullOrEmpty(functionFullName), "!String.IsNullOrEmpty(functionFullName)"); Debug.Assert(!String.IsNullOrEmpty(functionDefinition), "!String.IsNullOrEmpty(functionDefinition)"); Debug.Assert(functionParameters != null, "functionParameters != null"); Debug.Assert(edmItemCollection != null, "edmItemCollection != null"); MetadataWorkspace workspace = new MetadataWorkspace(); workspace.RegisterItemCollection(edmItemCollection); Perspective perspective = new ModelPerspective(workspace); // Since we compile lambda expression and generate variables from the function parameter definitions, // the returned DbLambda will contain variable types that match function parameter types. DbLambda functionBody = CqlQuery.CompileQueryCommandLambda( functionDefinition, perspective, null /* use default parser options */, null /* parameters */, functionParameters.Select(pInfo => pInfo.TypeUsage.Variable(pInfo.Name))); Debug.Assert(functionBody != null, "functionBody != null"); return(functionBody); }
static internal DbExpression CompileFunctionView( string viewDef, StorageMappingItemCollection mappingItemCollection, ParserOptions.CompilationMode compilationMode, IEnumerable <DbParameterReferenceExpression> parameters) { Debug.Assert(!String.IsNullOrEmpty(viewDef), "!String.IsNullOrEmpty(viewDef)"); Debug.Assert(mappingItemCollection != null, "mappingItemCollection != null"); Perspective perspective = new TargetPerspective(mappingItemCollection.Workspace); ParserOptions parserOptions = new ParserOptions(); parserOptions.ParserCompilationMode = compilationMode; // Parameters have to be accessible in the body as regular scope variables, not as command parameters. // Hence compile view as lambda with parameters as lambda vars, then invoke the lambda specifying // command parameters as values of the lambda vars. DbLambda functionBody = CqlQuery.CompileQueryCommandLambda( viewDef, perspective, parserOptions, null /* parameters */, parameters.Select(pInfo => pInfo.ResultType.Variable(pInfo.ParameterName))); Debug.Assert(functionBody != null, "functionBody != null"); DbExpression expr = functionBody.Invoke(parameters); return(expr); }
internal FunctionDefinition(string name, DbLambda lambda, int startPosition, int endPosition) { Debug.Assert(name != null, "name can not be null"); Debug.Assert(lambda != null, "lambda cannot be null"); this._name = name; this._lambda = lambda; this._startPosition = startPosition; this._endPosition = endPosition; }
internal FunctionDefinition(string name, DbLambda lambda, int startPosition, int endPosition) { DebugCheck.NotNull(name); DebugCheck.NotNull(lambda); _name = name; _lambda = lambda; _startPosition = startPosition; _endPosition = endPosition; }
internal DbLambdaExpression(TypeUsage resultType, DbLambda lambda, DbExpressionList args) : base(DbExpressionKind.Lambda, resultType) { Debug.Assert(lambda != null, "DbLambdaExpression lambda cannot be null"); Debug.Assert(args != null, "DbLambdaExpression arguments cannot be null"); Debug.Assert(object.ReferenceEquals(resultType, lambda.Body.ResultType), "DbLambdaExpression result type must be Lambda body result type"); Debug.Assert(lambda.Variables.Count == args.Count, "DbLambdaExpression argument count does not match Lambda parameter count"); this._lambda = lambda; this._arguments = args; }
protected DbFilterExpression ComposeFilter(DbExpression input, DbProjectExpression first, DbFilterExpression second) { // source.Project(first).Filter(second) -> source.Filter(e => second(first(e))) // create lambda expression representing the filter (e => second(e)) DbLambda secondLambda = DbExpressionBuilder.Lambda(second.Predicate, second.Input.Variable); // invoke lambda with variable from the project DbFilterExpression composed = first.Input.Filter(secondLambda.Invoke(first.Projection)); return(RebindFilter(input, composed)); }
internal DbLambdaExpression(TypeUsage resultType, DbLambda lambda, DbExpressionList args) : base(DbExpressionKind.Lambda, resultType) { DebugCheck.NotNull(lambda); DebugCheck.NotNull(args); Debug.Assert( ReferenceEquals(resultType, lambda.Body.ResultType), "DbLambdaExpression result type must be Lambda body result type"); Debug.Assert(lambda.Variables.Count == args.Count, "DbLambdaExpression argument count does not match Lambda parameter count"); _lambda = lambda; _arguments = args; }
/// <summary> /// Parse a specific query with a specific set variables and produce a <see cref="DbLambda"/>. /// </summary> public DbLambda ParseLambda(string query, params DbVariableReferenceExpression[] variables) { EntityUtil.CheckArgumentNull(query, "query"); if (variables != null) { IEnumerable <DbVariableReferenceExpression> varsEnum = variables; EntityUtil.CheckArgumentContainsNull(ref varsEnum, "variables"); } DbLambda result = CqlQuery.CompileQueryCommandLambda(query, _perspective, null /* parser options - use default */, null /* parameters */, variables); return(result); }
internal DbLambda GenerateFunctionDefinition(EdmFunction function) { if (!function.HasUserDefinedBody) { throw new InvalidOperationException(Strings.Cqt_UDF_FunctionHasNoDefinition((object)function.Identity)); } DbLambda dbLambda = ExternalCalls.CompileFunctionDefinition(function.CommandTextAttribute, (IList <FunctionParameter>)function.Parameters, this); if (!TypeSemantics.IsStructurallyEqual(function.ReturnParameter.TypeUsage, dbLambda.Body.ResultType)) { throw new InvalidOperationException(Strings.Cqt_UDF_FunctionDefinitionResultTypeMismatch((object)function.ReturnParameter.TypeUsage.ToString(), (object)function.FullName, (object)dbLambda.Body.ResultType.ToString())); } return(dbLambda); }
internal static TypeUsage ValidateInvoke( DbLambda lambda, IEnumerable <DbExpression> arguments, out DbExpressionList validArguments) { validArguments = (DbExpressionList)null; EnumerableValidator <DbExpression, DbExpression, DbExpressionList> validator = ArgumentValidation.CreateValidator <DbExpression, DbExpression, DbExpressionList>(arguments, nameof(arguments), (Func <DbExpression, int, DbExpression>)((exp, idx) => { ArgumentValidation.RequireCompatibleType(exp, lambda.Variables[idx].ResultType, nameof(arguments), idx); return(exp); }), (Func <List <DbExpression>, DbExpressionList>)(expList => new DbExpressionList((IList <DbExpression>)expList))); validator.ExpectedElementCount = lambda.Variables.Count; validArguments = validator.Validate(); return(lambda.Body.ResultType); }
public override DbExpression Visit(DbLambdaExpression expression) { EntityUtil.CheckArgumentNull(expression, "expression"); DbExpression result = expression; IList <DbExpression> newArguments = this.VisitExpressionList(expression.Arguments); DbLambda newLambda = this.VisitLambda(expression.Lambda); if (!object.ReferenceEquals(expression.Arguments, newArguments) || !object.ReferenceEquals(expression.Lambda, newLambda)) { result = CqtBuilder.Invoke(newLambda, newArguments); } NotifyIfChanged(expression, result); return(result); }
internal DbExpression Parse() { if (_queryExpression != null) { return(_queryExpression); } List <DbParameterReferenceExpression> parameters = null; if (this.Parameters != null) { parameters = new List <DbParameterReferenceExpression>(this.Parameters.Count); foreach (ObjectParameter parameter in this.Parameters) { TypeUsage typeUsage = parameter.TypeUsage; if (null == typeUsage) { // Since ObjectParameters do not allow users to specify 'facets', make // sure that the parameter TypeUsage is not populated with the provider // default facet values. this.ObjectContext.Perspective.TryGetTypeByName( parameter.MappableType.FullName, false /* bIgnoreCase */, out typeUsage); } Debug.Assert(typeUsage != null, "typeUsage != null"); parameters.Add(typeUsage.Parameter(parameter.Name)); } } DbLambda lambda = CqlQuery.CompileQueryCommandLambda( _queryText, // Command Text this.ObjectContext.Perspective, // Perspective null, // Parser options - null indicates 'use default' parameters, // Parameters null // Variables ); Debug.Assert(lambda.Variables == null || lambda.Variables.Count == 0, "lambda.Variables must be empty"); return(lambda.Body); }
/// <summary> /// Performs semantic conversion, validation on a query command AST and creates a <see cref="DbLambda"/> /// </summary> /// <param name="astQueryCommand">Abstract Syntax Tree of the query command</param> /// <param name="perspective">perspective</param> /// <param name="parserOptions">parser options<seealso cref="ParserOptions"/></param> /// <param name="parameters">ordinary command parameters</param> /// <param name="variables">command free variables</param> /// <remarks>Parameters name/types must be bound before invoking this method</remarks> /// <exception cref="System.Data.EntityException">Thrown when Syntatic or Semantic rules are violated and the query cannot be accepted.</exception> /// <exception cref="System.Data.MetadataException">Thrown as inner exception of a EntityException when metadata related service requests fail.</exception> /// <exception cref="System.Data.MappingException">Thrown as inner exception of a EntityException when mapping related service requests fail.</exception> /// <remarks> /// This method is not thread safe. /// </remarks> /// <seealso cref="ParserOptions"/> /// <seealso cref="DbExpression"/> private static DbLambda AnalyzeQueryExpressionSemantics(AST.Node astQueryCommand, Perspective perspective, ParserOptions parserOptions, IEnumerable <DbParameterReferenceExpression> parameters, IEnumerable <DbVariableReferenceExpression> variables) { return(AnalyzeSemanticsCommon( astQueryCommand, perspective, parserOptions, parameters, variables, (analyzer, astExpr) => { DbLambda lambda = analyzer.AnalyzeQueryCommand(astExpr); Debug.Assert(null != lambda, "null != lambda post-condition FAILED"); return lambda; })); }
/// <summary> /// Compiles an eSQL query command producing a validated <see cref="DbLambda"/>. /// </summary> /// <param name="queryCommandText">eSQL query command text</param> /// <param name="perspective">perspective</param> /// <param name="parserOptions">parser options<seealso cref="ParserOptions"/></param> /// <param name="parameters">ordinary command parameters</param> /// <param name="variables">command free variables</param> /// <returns>The query expression tree produced by parsing the given query command.</returns> /// <exception cref="System.Data.EntityException">Thrown when Syntatic or Semantic rules are violated and the query expression cannot be accepted</exception> /// <exception cref="System.Data.MetadataException">Thrown when metadata related service requests fail</exception> /// <exception cref="System.Data.MappingException">Thrown when mapping related service requests fail</exception> /// <remarks> /// This method is not thread safe. /// </remarks> /// <seealso cref="ParserOptions"/> /// <seealso cref="DbExpression"/> internal static DbLambda CompileQueryCommandLambda(string queryCommandText, Perspective perspective, ParserOptions parserOptions, IEnumerable <DbParameterReferenceExpression> parameters, IEnumerable <DbVariableReferenceExpression> variables) { return(CompileCommon(queryCommandText, perspective, parserOptions, (astCommand, validatedParserOptions) => { DbLambda lambda = AnalyzeQueryExpressionSemantics(astCommand, perspective, validatedParserOptions, parameters, variables); TypeHelpers.AssertEdmType(lambda.Body.ResultType); Debug.Assert(lambda != null, "lambda != null post-condition FAILED"); return lambda; })); }
/// <summary> /// Convenience method for post-processing after a DbLambda has been visited. /// </summary> /// <param name="lambda"> The previously visited DbLambda. </param> protected virtual void VisitLambdaPost(DbLambda lambda) { }
/// <summary> /// Convenience method indicating that the body of a Lambda <see cref="DbFunctionExpression" /> is now about to be visited. /// </summary> /// <param name="lambda"> The DbLambda that is about to be visited </param> /// <exception cref="ArgumentNullException"> /// <paramref name="lambda" /> /// is null /// </exception> protected virtual void VisitLambdaPre(DbLambda lambda) { Check.NotNull(lambda, "lambda"); }
/// <summary> /// Convenience method indicating that the body of a Lambda <see cref="T:System.Data.Entity.Core.Common.CommandTrees.DbFunctionExpression" /> is now about to be visited. /// </summary> /// <param name="lambda"> The DbLambda that is about to be visited </param> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="lambda" /> /// is null /// </exception> protected virtual void VisitLambdaPre(DbLambda lambda) { Check.NotNull <DbLambda>(lambda, nameof(lambda)); }
/// <summary> /// Convenience method indicating that the body of a Lambda <see cref="DbFunctionExpression"/> is now about to be visited. /// </summary> /// <param name="lambda">The DbLambda that is about to be visited</param> /// <exception cref="ArgumentNullException"><paramref name="lambda"/> is null</exception> protected virtual void VisitLambdaPre(DbLambda lambda) { EntityUtil.CheckArgumentNull(lambda, "lambda"); }
/// <summary> /// Dumps the specified DbLambda instance /// </summary> /// <param name="lambda"> The DbLambda to dump. </param> internal void Dump(DbLambda lambda) { Begin("DbLambda"); Dump(lambda.Variables.Cast<DbExpression>(), "Variables", "Variable"); Dump(lambda.Body, "Body"); End("DbLambda"); }
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); } }
internal DbLambdaExpression(TypeUsage resultType, DbLambda lambda, DbExpressionList args) : base(DbExpressionKind.Lambda, resultType, true) { this._lambda = lambda; this._arguments = args; }