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;
        }
Пример #2
0
 public QueryCommandAction(DbQueryCommandTree commandTree)
 {
     this.commandTree = commandTree;
 }
Пример #3
0
        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;
 }
Пример #5
0
        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);
        }
Пример #7
0
        /// <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);
        }
Пример #11
0
 internal DbQueryCommandTree GenerateCqt()
 {
     return(DbQueryCommandTree.FromValidExpression(this.m_mappingItemCollection.Workspace, DataSpace.SSpace, this.GenerateCqlBlockTree().AsCqt(true), true));
 }
Пример #12
0
        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;
                }
            }
        }
Пример #15
0
 public SqlSelectGenerator(DbQueryCommandTree commandTree, NpgsqlProviderManifest providerManifest)
     : base(providerManifest)
 {
     _commandTree = commandTree;
 }
Пример #16
0
 internal static DbQueryCommandTree SimplifyView(EntitySetBase extent, DbQueryCommandTree view)
 {
     var vs = new ViewSimplifier(extent);
     view = vs.Simplify(view);
     return view;
 }
Пример #17
0
        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));
        }
Пример #19
0
 public SqlSelectGenerator(DbQueryCommandTree commandTree)
 {
     _commandTree = commandTree;
 }
Пример #20
0
 public SqlSelectGenerator(DbQueryCommandTree commandTree)
 {
     _commandTree = commandTree;
 }