private DbQueryCommandTree Simplify(DbQueryCommandTree view) { var simplifier = PatternMatchRuleProcessor.Create( // determines if an expression is of the form outerProject(outerProjection(innerProject(innerNew))) PatternMatchRule.Create(_patternCollapseNestedProjection, CollapseNestedProjection), // A case statement can potentially be simplified PatternMatchRule.Create(_patternCase, SimplifyCaseStatement), // Nested TPH discriminator pattern can be converted to the expected TPH discriminator pattern PatternMatchRule.Create(_patternNestedTphDiscriminator, SimplifyNestedTphDiscriminator), // Entity constructors may be augmented with FK-based related entity refs PatternMatchRule.Create(_patternEntityConstructor, AddFkRelatedEntityRefs) ); var queryExpression = view.Query; queryExpression = simplifier(queryExpression); view = DbQueryCommandTree.FromValidExpression(view.MetadataWorkspace, view.DataSpace, queryExpression); return view; }
public QueryCommandAction(DbQueryCommandTree commandTree) { this.commandTree = commandTree; }
private static List<FieldDescription> GetReturningFields( DbQueryCommandTree commandTree) { List<FieldDescription> fields = new List<FieldDescription>(); CollectionType collectionType = commandTree.Query.ResultType.EdmType as CollectionType; RowType rowType = collectionType.TypeUsage.EdmType as RowType; foreach (EdmMember member in rowType.Members) { PrimitiveType memberType = member.TypeUsage.EdmType as PrimitiveType; fields.Add(new FieldDescription(member.Name, memberType.ClrEquivalentType)); } return fields; }
public SqlSelectGenerator(DbQueryCommandTree commandTree, NpgsqlProviderManifest providerManifest) : base(providerManifest) { _commandTree = commandTree; }
internal static ObjectResult <TResultType> ExecuteCommandTree <TResultType>(ObjectContext context, DbQueryCommandTree query, MergeOption mergeOption) { Debug.Assert(context != null, "ObjectContext cannot be null"); Debug.Assert(query != null, "Command tree cannot be null"); ObjectQueryExecutionPlan execPlan = ObjectQueryExecutionPlan.Prepare(context, query, typeof(TResultType), mergeOption, null, null, System.Data.Common.CommandTrees.ExpressionBuilder.DbExpressionBuilder.AliasGenerator); return(execPlan.Execute <TResultType>(context, null)); }
internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption?forMergeOption) { // Metadata is required to generate the execution plan or to retrieve it from the cache. this.ObjectContext.EnsureMetadata(); // Determine the required merge option, with the following precedence: // 1. The merge option specified to Execute(MergeOption) as forMergeOption. // 2. The merge option set via ObjectQuery.MergeOption. // 3. The global default merge option. MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption); // If a cached plan is present, then it can be reused if it has the required merge option // (since span and parameters cannot change between executions). However, if the cached // plan does not have the required merge option we proceed as if it were not present. ObjectQueryExecutionPlan plan = this._cachedPlan; if (plan != null) { if (plan.MergeOption == mergeOption) { return(plan); } else { plan = null; } } // There is no cached plan (or it was cleared), so the execution plan must be retrieved from // the global query cache (if plan caching is enabled) or rebuilt for the required merge option. QueryCacheManager cacheManager = null; EntitySqlQueryCacheKey cacheKey = null; if (this.PlanCachingEnabled) { // Create a new cache key that reflects the current state of the Parameters collection // and the Span object (if any), and uses the specified merge option. cacheKey = new EntitySqlQueryCacheKey( this.ObjectContext.DefaultContainerName, _queryText, (null == this.Parameters ? 0 : this.Parameters.Count), (null == this.Parameters ? null : this.Parameters.GetCacheKey()), (null == this.Span ? null : this.Span.GetCacheKey()), mergeOption, this.ElementType); cacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan executionPlan = null; if (cacheManager.TryCacheLookup(cacheKey, out executionPlan)) { plan = executionPlan; } } if (plan == null) { // Either caching is not enabled or the execution plan was not found in the cache DbExpression queryExpression = this.Parse(); Debug.Assert(queryExpression != null, "EntitySqlQueryState.Parse returned null expression?"); DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, this.Span, null, DbExpressionBuilder.AliasGenerator); // If caching is enabled then update the cache now. // Note: the logic is the same as in ELinqQueryState. if (cacheKey != null) { var newEntry = new QueryCacheEntry(cacheKey, plan); QueryCacheEntry foundEntry = null; if (cacheManager.TryLookupAndAdd(newEntry, out foundEntry)) { // If TryLookupAndAdd returns 'true' then the entry was already present in the cache when the attempt to add was made. // In this case the existing execution plan should be used. plan = (ObjectQueryExecutionPlan)foundEntry.GetTarget(); } } } if (this.Parameters != null) { this.Parameters.SetReadOnly(true); } // Update the cached plan with the newly retrieved/prepared plan this._cachedPlan = plan; // Return the execution plan return(plan); }
/// <summary> /// Given an extent and its corresponding view, invokes the parser to check if the view definition is syntactically correct. /// Iff parsing succeeds: <paramref name="commandTree"/> and <paramref name="discriminatorMap"/> are set to the parse result and method returns true, /// otherwise if parser has thrown a catchable exception, it is returned via <paramref name="parserException"/> parameter, /// otherwise exception is re-thrown. /// </summary> private static bool TryParseView(string eSQL, bool isUserSpecified, EntitySetBase extent, StorageMappingItemCollection mappingItemCollection, ConfigViewGenerator config, out DbQueryCommandTree commandTree, out DiscriminatorMap discriminatorMap, out Exception parserException) { commandTree = null; discriminatorMap = null; parserException = null; // We do not catch any internal exceptions any more config.StartSingleWatch(PerfType.ViewParsing); try { // If it is a user specified view, allow all queries. Otherwise parse the view in the restricted mode. ParserOptions.CompilationMode compilationMode = ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (isUserSpecified) { compilationMode = ParserOptions.CompilationMode.UserViewGenerationMode; } Debug.Assert(!String.IsNullOrEmpty(eSQL), "eSQL query is not specified"); commandTree = (DbQueryCommandTree)ExternalCalls.CompileView(eSQL, mappingItemCollection, compilationMode); if (!isUserSpecified || AppSettings.SimplifyUserSpecifiedViews) { commandTree = ViewSimplifier.SimplifyView(extent, commandTree); } // See if the view matches the "discriminated" pattern (allows simplification of generated store commands) if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet) { if (DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap)) { Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created"); } } } catch (Exception e) { // Catching all the exception types since Query parser seems to be throwing veriety of // exceptions - EntityException, ArgumentException, ArgumentNullException etc. if (EntityUtil.IsCatchableExceptionType(e)) { parserException = e; } else { throw; } } finally { config.StopSingleWatch(PerfType.ViewParsing); } Debug.Assert(commandTree != null || parserException != null, "Either commandTree or parserException is expected."); // Note: m_commandTree might have been initialized by a previous call to this method, so in consequent calls it might occur that // both m_commandTree and parserException are not null - this would mean that the last parse attempt failed, but m_commandTree value is // preserved from the previous call. return(parserException == null); }
/// <summary> /// Sets the expected column types for a given query command tree /// </summary> private void SetQueryExpectedTypes(DbQueryCommandTree tree, EFMySqlCommand cmd) { DbProjectExpression projectExpression = tree.Query as DbProjectExpression; if (projectExpression != null) { EdmType resultsType = projectExpression.Projection.ResultType.EdmType; StructuralType resultsAsStructuralType = resultsType as StructuralType; if (resultsAsStructuralType != null) { cmd.ColumnTypes = new PrimitiveType[resultsAsStructuralType.Members.Count]; for (int ordinal = 0; ordinal < resultsAsStructuralType.Members.Count; ordinal++) { EdmMember member = resultsAsStructuralType.Members[ordinal]; PrimitiveType primitiveType = member.TypeUsage.EdmType as PrimitiveType; cmd.ColumnTypes[ordinal] = primitiveType; } } } }
internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption?forMergeOption) { Debug.Assert(this.Span == null, "Include span specified on compiled LINQ-based ObjectQuery instead of within the expression tree?"); Debug.Assert(this._cachedPlan == null, "Cached plan should not be set on compiled LINQ queries"); // Metadata is required to generate the execution plan or to retrieve it from the cache. this.ObjectContext.EnsureMetadata(); ObjectQueryExecutionPlan plan = null; CompiledQueryCacheEntry cacheEntry = this._cacheEntry; bool useCSharpNullComparisonBehavior = this.ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior; if (cacheEntry != null) { // The cache entry has already been retrieved, so compute the effective merge option with the following precedence: // 1. The merge option specified as the argument to Execute(MergeOption), and so to this method // 2. The merge option set using ObjectQuery.MergeOption // 3. The propagated merge option as recorded in the cache entry // 4. The global default merge option. MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); // Ask for the corresponding execution plan plan = cacheEntry.GetExecutionPlan(mergeOption, useCSharpNullComparisonBehavior); if (plan == null) { // Convert the LINQ expression to produce a command tree ExpressionConverter converter = this.CreateExpressionConverter(); DbExpression queryExpression = converter.Convert(); ReadOnlyCollection <KeyValuePair <ObjectParameter, QueryParameterExpression> > parameters = converter.GetParameters(); // Prepare the execution plan using the command tree and the computed effective merge option DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, parameters, converter.AliasGenerator); // Update and retrieve the execution plan plan = cacheEntry.SetExecutionPlan(plan, useCSharpNullComparisonBehavior); } } else { // This instance does not yet have a reference to a cache entry. // First, attempt to retrieve an existing cache entry. QueryCacheManager cacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); CompiledQueryCacheKey cacheKey = new CompiledQueryCacheKey(this._cacheToken); if (cacheManager.TryCacheLookup(cacheKey, out cacheEntry)) { // An entry was found in the cache, so compute the effective merge option based on its propagated merge option, // and use the UseCSharpNullComparisonBehavior flag to retrieve the corresponding execution plan. this._cacheEntry = cacheEntry; MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); plan = cacheEntry.GetExecutionPlan(mergeOption, useCSharpNullComparisonBehavior); } // If no cache entry was found or if the cache entry did not contain the required execution plan, the plan is still null at this point. if (plan == null) { // The execution plan needs to be produced, so create an appropriate expression converter and generate the query command tree. ExpressionConverter converter = this.CreateExpressionConverter(); DbExpression queryExpression = converter.Convert(); ReadOnlyCollection <KeyValuePair <ObjectParameter, QueryParameterExpression> > parameters = converter.GetParameters(); DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); // If a cache entry for this compiled query's cache key was not successfully retrieved, then it must be created now. // Note that this is only possible after converting the LINQ expression and discovering the propagated merge option, // which is required in order to create the cache entry. if (cacheEntry == null) { // Create the cache entry using this instance's cache token and the propagated merge option (which may be null) cacheEntry = new CompiledQueryCacheEntry(cacheKey, converter.PropagatedMergeOption); // Attempt to add the entry to the cache. If an entry was added in the meantime, use that entry instead. QueryCacheEntry foundEntry; if (cacheManager.TryLookupAndAdd(cacheEntry, out foundEntry)) { cacheEntry = (CompiledQueryCacheEntry)foundEntry; } // We now have a cache entry, so hold onto it for future use. this._cacheEntry = cacheEntry; } // Recompute the effective merge option in case a cache entry was just constructed above MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); // Ask the (retrieved or constructed) cache entry for the corresponding execution plan. plan = cacheEntry.GetExecutionPlan(mergeOption, useCSharpNullComparisonBehavior); if (plan == null) { // The plan is not present, so prepare it now using the computed effective merge option plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, parameters, converter.AliasGenerator); // Update the execution plan on the cache entry. // If the execution plan was set in the meantime, SetExecutionPlan will return that value, otherwise it will return 'plan'. plan = cacheEntry.SetExecutionPlan(plan, useCSharpNullComparisonBehavior); } } } // Get parameters from the plan and set them. ObjectParameterCollection currentParams = this.EnsureParameters(); if (plan.CompiledQueryParameters != null && plan.CompiledQueryParameters.Count > 0) { currentParams.SetReadOnly(false); currentParams.Clear(); foreach (KeyValuePair <ObjectParameter, QueryParameterExpression> pair in plan.CompiledQueryParameters) { // Parameters retrieved from the CompiledQueryParameters collection must be cloned before being added to the query. // The cached plan is shared and when used in multithreaded scenarios failing to clone the parameter would result // in the code below updating the values of shared parameter instances saved in the cached plan and used by all // queries using that plan, regardless of the values they were actually invoked with, causing incorrect results // when those queries were later executed. // ObjectParameter convertedParam = pair.Key.ShallowCopy(); QueryParameterExpression parameterExpression = pair.Value; currentParams.Add(convertedParam); if (parameterExpression != null) { convertedParam.Value = parameterExpression.EvaluateParameter(_parameterValues); } } } currentParams.SetReadOnly(true); Debug.Assert(plan != null, "Failed to produce an execution plan?"); return(plan); }
internal override ObjectQueryExecutionPlan GetExecutionPlan( MergeOption?forMergeOption) { MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption); ObjectQueryExecutionPlan queryExecutionPlan1 = this._cachedPlan; if (queryExecutionPlan1 != null) { if (queryExecutionPlan1.MergeOption == mergeOption && queryExecutionPlan1.Streaming == this.EffectiveStreamingBehavior) { return(queryExecutionPlan1); } queryExecutionPlan1 = (ObjectQueryExecutionPlan)null; } QueryCacheManager queryCacheManager = (QueryCacheManager)null; EntitySqlQueryCacheKey key = (EntitySqlQueryCacheKey)null; if (this.PlanCachingEnabled) { key = new EntitySqlQueryCacheKey(this.ObjectContext.DefaultContainerName, this._queryText, this.Parameters == null ? 0 : this.Parameters.Count, this.Parameters == null ? (string)null : this.Parameters.GetCacheKey(), this.Span == null ? (string)null : this.Span.GetCacheKey(), mergeOption, this.EffectiveStreamingBehavior, this.ElementType); queryCacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan queryExecutionPlan2 = (ObjectQueryExecutionPlan)null; if (queryCacheManager.TryCacheLookup <EntitySqlQueryCacheKey, ObjectQueryExecutionPlan>(key, out queryExecutionPlan2)) { queryExecutionPlan1 = queryExecutionPlan2; } } if (queryExecutionPlan1 == null) { queryExecutionPlan1 = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, this.Parse(), true), this.ElementType, mergeOption, this.EffectiveStreamingBehavior, this.Span, (IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> >)null, DbExpressionBuilder.AliasGenerator); if (key != null) { QueryCacheEntry inQueryCacheEntry = new QueryCacheEntry((QueryCacheKey)key, (object)queryExecutionPlan1); QueryCacheEntry outQueryCacheEntry = (QueryCacheEntry)null; if (queryCacheManager.TryLookupAndAdd(inQueryCacheEntry, out outQueryCacheEntry)) { queryExecutionPlan1 = (ObjectQueryExecutionPlan)outQueryCacheEntry.GetTarget(); } } } if (this.Parameters != null) { this.Parameters.SetReadOnly(true); } this._cachedPlan = queryExecutionPlan1; return(queryExecutionPlan1); }
internal DbQueryCommandTree GenerateCqt() { return(DbQueryCommandTree.FromValidExpression(this.m_mappingItemCollection.Workspace, DataSpace.SSpace, this.GenerateCqlBlockTree().AsCqt(true), true)); }
internal override ObjectQueryExecutionPlan GetExecutionPlan( MergeOption?forMergeOption) { ObjectQueryExecutionPlan queryExecutionPlan = (ObjectQueryExecutionPlan)null; CompiledQueryCacheEntry compiledQueryCacheEntry = this._cacheEntry; bool comparisonBehavior = this.ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior; if (compiledQueryCacheEntry != null) { MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, compiledQueryCacheEntry.PropagatedMergeOption); queryExecutionPlan = compiledQueryCacheEntry.GetExecutionPlan(mergeOption, comparisonBehavior); if (queryExecutionPlan == null) { ExpressionConverter expressionConverter = this.CreateExpressionConverter(); DbExpression query = expressionConverter.Convert(); IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> > parameters = expressionConverter.GetParameters(); ObjectQueryExecutionPlan newPlan = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, query, !comparisonBehavior), this.ElementType, mergeOption, this.EffectiveStreamingBehavior, expressionConverter.PropagatedSpan, parameters, expressionConverter.AliasGenerator); queryExecutionPlan = compiledQueryCacheEntry.SetExecutionPlan(newPlan, comparisonBehavior); } } else { QueryCacheManager queryCacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); CompiledQueryCacheKey key = new CompiledQueryCacheKey(this._cacheToken); if (queryCacheManager.TryCacheLookup <CompiledQueryCacheKey, CompiledQueryCacheEntry>(key, out compiledQueryCacheEntry)) { this._cacheEntry = compiledQueryCacheEntry; MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, compiledQueryCacheEntry.PropagatedMergeOption); queryExecutionPlan = compiledQueryCacheEntry.GetExecutionPlan(mergeOption, comparisonBehavior); } if (queryExecutionPlan == null) { ExpressionConverter expressionConverter = this.CreateExpressionConverter(); DbExpression query = expressionConverter.Convert(); IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> > parameters = expressionConverter.GetParameters(); DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, query, !comparisonBehavior); if (compiledQueryCacheEntry == null) { compiledQueryCacheEntry = new CompiledQueryCacheEntry((QueryCacheKey)key, expressionConverter.PropagatedMergeOption); QueryCacheEntry outQueryCacheEntry; if (queryCacheManager.TryLookupAndAdd((QueryCacheEntry)compiledQueryCacheEntry, out outQueryCacheEntry)) { compiledQueryCacheEntry = (CompiledQueryCacheEntry)outQueryCacheEntry; } this._cacheEntry = compiledQueryCacheEntry; } MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, compiledQueryCacheEntry.PropagatedMergeOption); queryExecutionPlan = compiledQueryCacheEntry.GetExecutionPlan(mergeOption, comparisonBehavior); if (queryExecutionPlan == null) { ObjectQueryExecutionPlan newPlan = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, this.EffectiveStreamingBehavior, expressionConverter.PropagatedSpan, parameters, expressionConverter.AliasGenerator); queryExecutionPlan = compiledQueryCacheEntry.SetExecutionPlan(newPlan, comparisonBehavior); } } } ObjectParameterCollection parameterCollection = this.EnsureParameters(); if (queryExecutionPlan.CompiledQueryParameters != null && queryExecutionPlan.CompiledQueryParameters.Any <Tuple <ObjectParameter, QueryParameterExpression> >()) { parameterCollection.SetReadOnly(false); parameterCollection.Clear(); foreach (Tuple <ObjectParameter, QueryParameterExpression> compiledQueryParameter in queryExecutionPlan.CompiledQueryParameters) { ObjectParameter objectParameter = compiledQueryParameter.Item1.ShallowCopy(); QueryParameterExpression parameterExpression = compiledQueryParameter.Item2; parameterCollection.Add(objectParameter); if (parameterExpression != null) { objectParameter.Value = parameterExpression.EvaluateParameter(this._parameterValues); } } } parameterCollection.SetReadOnly(true); return(queryExecutionPlan); }
private static EntityCommandDefinition CreateCommandDefinition(ObjectContext context, DbQueryCommandTree tree) { var connection = context.Connection; // The connection is required to get to the CommandDefinition builder. if (connection == null) { throw new InvalidOperationException(Strings.ObjectQuery_InvalidConnection); } var services = DbProviderServices.GetProviderServices(connection); DbCommandDefinition definition; try { definition = services.CreateCommandDefinition(tree, context.InterceptionContext); } catch (EntityCommandCompilationException) { // If we're running against EntityCommand, we probably already caught the providers' // exception and wrapped it, we don't want to do that again, so we'll just rethrow // here instead. throw; } catch (Exception e) { // we should not be wrapping all exceptions if (e.IsCatchableExceptionType()) { // we don't wan't folks to have to know all the various types of exceptions that can // occur, so we just rethrow a CommandDefinitionException and make whatever we caught // the inner exception of it. throw new EntityCommandCompilationException(Strings.EntityClient_CommandDefinitionPreparationFailed, e); } throw; } if (definition == null) { throw new NotSupportedException(Strings.ADP_ProviderDoesNotSupportCommandTrees); } return((EntityCommandDefinition)definition); }
/// <summary> /// This method is called after a new /// <see cref="T:System.Data.Entity.Core.Common.CommandTrees.DbCommandTree" /> has been created. /// The tree that is used after interception can be changed by setting /// <see cref="P:System.Data.Entity.Infrastructure.Interception.DbCommandTreeInterceptionContext.Result" /> /// while intercepting. /// </summary> /// <param name="interceptionContext">Contextual information associated with the call.</param> public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext) { var dbQueryCommandTree = interceptionContext.Result as DbQueryCommandTree; if (dbQueryCommandTree != null && interceptionContext.DbContexts.Count() == 1) { var context = interceptionContext.DbContexts.First(); // Visit first to find filter ID && hook var visitorFilter = new QueryFilterInterceptorDbFilterExpression(); var queryFiltered = dbQueryCommandTree.Query.Accept(visitorFilter); if (!string.IsNullOrEmpty(visitorFilter.HookID)) { if (!QueryFilterManager.DbExpressionByHook.ContainsKey(visitorFilter.HookID)) { QueryFilterManager.DbExpressionByHook.TryAdd(visitorFilter.HookID, queryFiltered); } } else { var filterByContext = QueryFilterManager.AddOrGetFilterContext(context); filterByContext.ClearCacheRequired = true; var filterQuery = new QueryFilterInterceptorApply { InstanceFilters = filterByContext }; if (visitorFilter.FilterID != null && visitorFilter.FilterID.Count > 0) { foreach (var filter in visitorFilter.FilterID) { if (filter == QueryFilterManager.DisableAllFilter) { // Disable all filter in the context! filterQuery.ApplyFilterList.Add(interceptorFilter => false); } else if (filter.StartsWith(QueryFilterManager.EnableFilterById, StringComparison.InvariantCulture)) { // Enable all specific filter var filters = filter.Substring(QueryFilterManager.EnableFilterById.Length).Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries); if (filters.Length == 0) { filterQuery.ApplyFilterList.Add(interceptorFilter => false); } foreach (var applyFilter in filters) { filterQuery.ApplyFilterList.Add(interceptorFilter => interceptorFilter.UniqueKey.ToString() == applyFilter ? true : (bool?)null); } } } } // VISIT filter var visitor = new QueryFilterInterceptorDbScanExpression { Context = context, InstanceFilterContext = filterByContext, FilterQuery = filterQuery }; var newQuery = queryFiltered.Accept(visitor); // CREATE a new Query var commandTree = new DbQueryCommandTree(dbQueryCommandTree.MetadataWorkspace, dbQueryCommandTree.DataSpace, newQuery, true); interceptionContext.Result = commandTree; } } }
internal static DbQueryCommandTree SimplifyView(EntitySetBase extent, DbQueryCommandTree view) { var vs = new ViewSimplifier(extent); view = vs.Simplify(view); return view; }
internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption?forMergeOption) { Debug.Assert(Span == null, "Include span specified on compiled LINQ-based ObjectQuery instead of within the expression tree?"); // If this query has already been prepared, its current execution plan may no longer be valid. var plan = _cachedPlan; if (plan != null) { // Was a merge option specified in the call to Execute(MergeOption) or set via ObjectQuery.MergeOption? var explicitMergeOption = GetMergeOption(forMergeOption, UserSpecifiedMergeOption); // If a merge option was explicitly specified, and it does not match the plan's merge option, then the plan is no longer valid. // If the context flag UseCSharpNullComparisonBehavior was modified, then the plan is no longer valid. if ((explicitMergeOption.HasValue && explicitMergeOption.Value != plan.MergeOption) || _recompileRequired() || ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior != _useCSharpNullComparisonBehavior) { plan = null; } } // The plan may have been invalidated above, or this query may never have been prepared. if (plan == null) { // Reset internal state _recompileRequired = null; ResetParameters(); // Translate LINQ expression to a DbExpression var converter = CreateExpressionConverter(); var queryExpression = converter.Convert(); // This delegate tells us when a part of the expression tree has changed requiring a recompile. _recompileRequired = converter.RecompileRequired; // Determine the merge option, with the following precedence: // 1. A merge option was specified explicitly as the argument to Execute(MergeOption). // 2. The user has set the MergeOption property on the ObjectQuery instance. // 3. A merge option has been extracted from the 'root' query and propagated to the root of the expression tree. // 4. The global default merge option. var mergeOption = EnsureMergeOption( forMergeOption, UserSpecifiedMergeOption, converter.PropagatedMergeOption); _useCSharpNullComparisonBehavior = ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior; // If parameters were aggregated from referenced (non-LINQ) ObjectQuery instances then add them to the parameters collection _linqParameters = converter.GetParameters(); if (_linqParameters != null && _linqParameters.Any()) { var currentParams = EnsureParameters(); currentParams.SetReadOnly(false); foreach (var pair in _linqParameters) { // Note that it is safe to add the parameter directly only // because parameters are cloned before they are added to the // converter's parameter collection, or they came from this // instance's parameter collection in the first place. var convertedParam = pair.Item1; currentParams.Add(convertedParam); } currentParams.SetReadOnly(true); } // Try retrieving the execution plan from the global query cache (if plan caching is enabled). QueryCacheManager cacheManager = null; LinqQueryCacheKey cacheKey = null; if (PlanCachingEnabled && !_recompileRequired()) { // Create a new cache key that reflects the current state of the Parameters collection // and the Span object (if any), and uses the specified merge option. string expressionKey; if (ExpressionKeyGen.TryGenerateKey(queryExpression, out expressionKey)) { cacheKey = new LinqQueryCacheKey( expressionKey, (null == Parameters ? 0 : Parameters.Count), (null == Parameters ? null : Parameters.GetCacheKey()), (null == converter.PropagatedSpan ? null : converter.PropagatedSpan.GetCacheKey()), mergeOption, EffectiveStreamingBehaviour, _useCSharpNullComparisonBehavior, ElementType); cacheManager = ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan executionPlan = null; if (cacheManager.TryCacheLookup(cacheKey, out executionPlan)) { plan = executionPlan; } } } // If execution plan wasn't retrieved from the cache, build a new one and cache it. if (plan == null) { var tree = DbQueryCommandTree.FromValidExpression( ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression, !_useCSharpNullComparisonBehavior); plan = _objectQueryExecutionPlanFactory.Prepare( ObjectContext, tree, ElementType, mergeOption, EffectiveStreamingBehaviour, converter.PropagatedSpan, null, converter.AliasGenerator); // If caching is enabled then update the cache now. // Note: the logic is the same as in EntitySqlQueryState. if (cacheKey != null) { var newEntry = new QueryCacheEntry(cacheKey, plan); QueryCacheEntry foundEntry = null; if (cacheManager.TryLookupAndAdd(newEntry, out foundEntry)) { // If TryLookupAndAdd returns 'true' then the entry was already present in the cache when the attempt to add was made. // In this case the existing execution plan should be used. plan = (ObjectQueryExecutionPlan)foundEntry.GetTarget(); } } } // Remember the current plan in the local cache, so that we don't have to recalc the key and look into the global cache // if the same instance of query gets executed more than once. _cachedPlan = plan; } // Evaluate parameter values for the query. if (_linqParameters != null) { foreach (var pair in _linqParameters) { var parameter = pair.Item1; var parameterExpression = pair.Item2; if (null != parameterExpression) { parameter.Value = parameterExpression.EvaluateParameter(null); } } } return(plan); }
internal Node GetInternalTree(Command targetIqtCommand, IList <Node> targetIqtArguments) { if (m_internalTreeNode == null) { var viewGenErrors = new List <EdmSchemaError>(); DiscriminatorMap discriminatorMap; DbQueryCommandTree tree = GenerateFunctionView(viewGenErrors, out discriminatorMap); if (viewGenErrors.Count > 0) { throw new MappingException(Helper.CombineErrorMessage(viewGenErrors)); } Debug.Assert(tree != null, "tree != null"); // Convert this into an ITree first Command itree = ITreeGenerator.Generate(tree, discriminatorMap); var rootProject = itree.Root; // PhysicalProject(RelInput) PlanCompiler.Assert(rootProject.Op.OpType == OpType.PhysicalProject, "Expected a physical projectOp at the root of the tree - found " + rootProject.Op.OpType); var rootProjectOp = (PhysicalProjectOp)rootProject.Op; Debug.Assert(rootProjectOp.Outputs.Count == 1, "rootProjectOp.Outputs.Count == 1"); var rootInput = rootProject.Child0; // the RelInput in PhysicalProject(RelInput) // #554756: VarVec enumerators are not cached on the shared Command instance. itree.DisableVarVecEnumCaching(); // Function import returns a collection, so convert it to a scalar by wrapping into CollectOp. Node relNode = rootInput; Var relVar = rootProjectOp.Outputs[0]; // ProjectOp does not implement Type property, so get the type from the column map. TypeUsage functionViewType = rootProjectOp.ColumnMap.Type; if (!Command.EqualTypes(functionViewType, this.FunctionImport.ReturnParameter.TypeUsage)) { Debug.Assert(TypeSemantics.IsPromotableTo(functionViewType, this.FunctionImport.ReturnParameter.TypeUsage), "Mapping expression result type must be promotable to the c-space function return type."); // Build "relNode = Project(relNode, SoftCast(relVar))" CollectionType expectedCollectionType = (CollectionType)this.FunctionImport.ReturnParameter.TypeUsage.EdmType; var expectedElementType = expectedCollectionType.TypeUsage; Node varRefNode = itree.CreateNode(itree.CreateVarRefOp(relVar)); Node castNode = itree.CreateNode(itree.CreateSoftCastOp(expectedElementType), varRefNode); Node varDefListNode = itree.CreateVarDefListNode(castNode, out relVar); ProjectOp projectOp = itree.CreateProjectOp(relVar); relNode = itree.CreateNode(projectOp, relNode, varDefListNode); } // Build "Collect(PhysicalProject(relNode)) m_internalTreeNode = itree.BuildCollect(relNode, relVar); } Debug.Assert(m_internalTreeNode != null, "m_internalTreeNode != null"); // Prepare argument replacement dictionary Debug.Assert(m_commandParameters.Length == targetIqtArguments.Count, "m_commandParameters.Length == targetIqtArguments.Count"); Dictionary <string, Node> viewArguments = new Dictionary <string, Node>(m_commandParameters.Length); for (int i = 0; i < m_commandParameters.Length; ++i) { var commandParam = (DbParameterReferenceExpression)m_commandParameters[i]; var argumentNode = targetIqtArguments[i]; // If function import parameter is of enum type, the argument value for it will be of enum type. We however have // converted enum types to underlying types for m_commandParameters. So we now need to softcast the argument // expression to the underlying type as well. if (TypeSemantics.IsEnumerationType(argumentNode.Op.Type)) { argumentNode = targetIqtCommand.CreateNode( targetIqtCommand.CreateSoftCastOp(TypeHelpers.CreateEnumUnderlyingTypeUsage(argumentNode.Op.Type)), argumentNode); } Debug.Assert(TypeSemantics.IsPromotableTo(argumentNode.Op.Type, commandParam.ResultType), "Argument type must be promotable to parameter type."); viewArguments.Add(commandParam.ParameterName, argumentNode); } return(FunctionViewOpCopier.Copy(targetIqtCommand, m_internalTreeNode, viewArguments)); }
public SqlSelectGenerator(DbQueryCommandTree commandTree) { _commandTree = commandTree; }