Exemple #1
0
        private static async Task <TryCatch <CosmosQueryExecutionContext> > TryCreateCoreContextAsync(
            CosmosQueryContext cosmosQueryContext,
            InputParameters inputParameters,
            CancellationToken cancellationToken)
        {
            // The default
            using (cosmosQueryContext.CreateDiagnosticScope("CreateQueryPipeline"))
            {
                // Try to parse the continuation token.
                CosmosElement continuationToken = inputParameters.InitialUserContinuationToken;
                PartitionedQueryExecutionInfo queryPlanFromContinuationToken = inputParameters.PartitionedQueryExecutionInfo;
                if (continuationToken != null)
                {
                    if (!PipelineContinuationToken.TryCreateFromCosmosElement(
                            continuationToken,
                            out PipelineContinuationToken pipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"Malformed {nameof(PipelineContinuationToken)}: {continuationToken}.")));
                    }

                    if (PipelineContinuationToken.IsTokenFromTheFuture(pipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(PipelineContinuationToken)} Continuation token is from a newer version of the SDK. " +
                                       $"Upgrade the SDK to avoid this issue." +
                                       $"{continuationToken}.")));
                    }

                    if (!PipelineContinuationToken.TryConvertToLatest(
                            pipelineContinuationToken,
                            out PipelineContinuationTokenV1_1 latestVersionPipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(PipelineContinuationToken)}: '{continuationToken}' is no longer supported.")));
                    }

                    continuationToken = latestVersionPipelineContinuationToken.SourceContinuationToken;
                    if (latestVersionPipelineContinuationToken.QueryPlan != null)
                    {
                        queryPlanFromContinuationToken = latestVersionPipelineContinuationToken.QueryPlan;
                    }
                }

                CosmosQueryClient        cosmosQueryClient        = cosmosQueryContext.QueryClient;
                ContainerQueryProperties containerQueryProperties = await cosmosQueryClient.GetCachedContainerQueryPropertiesAsync(
                    cosmosQueryContext.ResourceLink,
                    inputParameters.PartitionKey,
                    cancellationToken);

                cosmosQueryContext.ContainerResourceId = containerQueryProperties.ResourceId;

                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo;
                if (inputParameters.ForcePassthrough)
                {
                    partitionedQueryExecutionInfo = new PartitionedQueryExecutionInfo()
                    {
                        QueryInfo = new QueryInfo()
                        {
                            Aggregates     = null,
                            DistinctType   = DistinctQueryType.None,
                            GroupByAliases = null,
                            GroupByAliasToAggregateType = null,
                            GroupByExpressions          = null,
                            HasSelectValue     = false,
                            Limit              = null,
                            Offset             = null,
                            OrderBy            = null,
                            OrderByExpressions = null,
                            RewrittenQuery     = null,
                            Top = null,
                        },
                        QueryRanges = new List <Documents.Routing.Range <string> >(),
                    };
                }
                else if (queryPlanFromContinuationToken != null)
                {
                    partitionedQueryExecutionInfo = queryPlanFromContinuationToken;
                }
                else
                {
                    // If the query would go to gateway, but we have a partition key,
                    // then try seeing if we can execute as a passthrough using client side only logic.
                    // This is to short circuit the need to go to the gateway to get the query plan.
                    if (cosmosQueryContext.QueryClient.ByPassQueryParsing() &&
                        inputParameters.PartitionKey.HasValue)
                    {
                        bool     parsed;
                        SqlQuery sqlQuery;
                        using (cosmosQueryContext.CreateDiagnosticScope("QueryParsing"))
                        {
                            parsed = SqlQuery.TryParse(inputParameters.SqlQuerySpec.QueryText, out sqlQuery);
                        }

                        if (parsed)
                        {
                            bool hasDistinct            = sqlQuery.SelectClause.HasDistinct;
                            bool hasGroupBy             = sqlQuery.GroupByClause != default;
                            bool hasAggregates          = AggregateProjectionDetector.HasAggregate(sqlQuery.SelectClause.SelectSpec);
                            bool createPassthroughQuery = !hasAggregates && !hasDistinct && !hasGroupBy;

                            if (createPassthroughQuery)
                            {
                                TestInjections.ResponseStats responseStats = inputParameters?.TestInjections?.Stats;
                                if (responseStats != null)
                                {
                                    responseStats.PipelineType = TestInjections.PipelineType.Passthrough;
                                }

                                // Only thing that matters is that we target the correct range.
                                Documents.PartitionKeyDefinition   partitionKeyDefinition = GetPartitionKeyDefinition(inputParameters, containerQueryProperties);
                                List <Documents.PartitionKeyRange> targetRanges           = await cosmosQueryContext.QueryClient.GetTargetPartitionKeyRangesByEpkStringAsync(
                                    cosmosQueryContext.ResourceLink,
                                    containerQueryProperties.ResourceId,
                                    inputParameters.PartitionKey.Value.InternalKey.GetEffectivePartitionKeyString(partitionKeyDefinition));

                                return(await CosmosQueryExecutionContextFactory.TryCreatePassthroughQueryExecutionContextAsync(
                                           cosmosQueryContext,
                                           inputParameters,
                                           partitionedQueryExecutionInfo : new PartitionedQueryExecutionInfo(),
                                           targetRanges,
                                           containerQueryProperties.ResourceId,
                                           cancellationToken));
                            }
                        }
                    }

                    if (cosmosQueryContext.QueryClient.ByPassQueryParsing())
                    {
                        // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop, so need to bypass in that case.
                        // We are also now bypassing this for 32 bit host process running even on Windows as there are many 32 bit apps that will not work without this
                        partitionedQueryExecutionInfo = await QueryPlanRetriever.GetQueryPlanThroughGatewayAsync(
                            cosmosQueryContext,
                            inputParameters.SqlQuerySpec,
                            cosmosQueryContext.ResourceLink,
                            inputParameters.PartitionKey,
                            cancellationToken);
                    }
                    else
                    {
                        using (cosmosQueryContext.CreateDiagnosticScope("ServiceInterop"))
                        {
                            Documents.PartitionKeyDefinition partitionKeyDefinition = GetPartitionKeyDefinition(inputParameters, containerQueryProperties);

                            partitionedQueryExecutionInfo = await QueryPlanRetriever.GetQueryPlanWithServiceInteropAsync(
                                cosmosQueryContext.QueryClient,
                                inputParameters.SqlQuerySpec,
                                partitionKeyDefinition,
                                inputParameters.PartitionKey != null,
                                cancellationToken);
                        }
                    }
                }

                return(await TryCreateFromPartitionedQuerExecutionInfoAsync(
                           partitionedQueryExecutionInfo,
                           containerQueryProperties,
                           cosmosQueryContext,
                           inputParameters,
                           cancellationToken));
            }
        }
Exemple #2
0
        public static async Task <TryCatch <CosmosQueryExecutionContext> > TryCreateFromPartitionedQuerExecutionInfoAsync(
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            ContainerQueryProperties containerQueryProperties,
            CosmosQueryContext cosmosQueryContext,
            InputParameters inputParameters,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            List <Documents.PartitionKeyRange> targetRanges = await CosmosQueryExecutionContextFactory.GetTargetPartitionKeyRangesAsync(
                cosmosQueryContext.QueryClient,
                cosmosQueryContext.ResourceLink,
                partitionedQueryExecutionInfo,
                containerQueryProperties,
                inputParameters.Properties,
                inputParameters.InitialFeedRange);

            bool singleLogicalPartitionKeyQuery = inputParameters.PartitionKey.HasValue ||
                                                  ((partitionedQueryExecutionInfo.QueryRanges.Count == 1) &&
                                                   partitionedQueryExecutionInfo.QueryRanges[0].IsSingleValue);
            bool serverStreamingQuery = !partitionedQueryExecutionInfo.QueryInfo.HasAggregates &&
                                        !partitionedQueryExecutionInfo.QueryInfo.HasDistinct &&
                                        !partitionedQueryExecutionInfo.QueryInfo.HasGroupBy;
            bool streamingSinglePartitionQuery = singleLogicalPartitionKeyQuery && serverStreamingQuery;

            bool clientStreamingQuery =
                serverStreamingQuery &&
                !partitionedQueryExecutionInfo.QueryInfo.HasOrderBy &&
                !partitionedQueryExecutionInfo.QueryInfo.HasTop &&
                !partitionedQueryExecutionInfo.QueryInfo.HasLimit &&
                !partitionedQueryExecutionInfo.QueryInfo.HasOffset;
            bool streamingCrossContinuationQuery = !singleLogicalPartitionKeyQuery && clientStreamingQuery;

            bool createPassthoughQuery = streamingSinglePartitionQuery || streamingCrossContinuationQuery;

            Task <TryCatch <CosmosQueryExecutionContext> > tryCreateContextTask;

            if (createPassthoughQuery)
            {
                TestInjections.ResponseStats responseStats = inputParameters?.TestInjections?.Stats;
                if (responseStats != null)
                {
                    responseStats.PipelineType = TestInjections.PipelineType.Passthrough;
                }

                tryCreateContextTask = CosmosQueryExecutionContextFactory.TryCreatePassthroughQueryExecutionContextAsync(
                    cosmosQueryContext,
                    inputParameters,
                    partitionedQueryExecutionInfo,
                    targetRanges,
                    containerQueryProperties.ResourceId,
                    cancellationToken);
            }
            else
            {
                TestInjections.ResponseStats responseStats = inputParameters?.TestInjections?.Stats;
                if (responseStats != null)
                {
                    responseStats.PipelineType = TestInjections.PipelineType.Specialized;
                }

                if (!string.IsNullOrEmpty(partitionedQueryExecutionInfo.QueryInfo.RewrittenQuery))
                {
                    // We need pass down the rewritten query.
                    SqlQuerySpec rewrittenQuerySpec = new SqlQuerySpec()
                    {
                        QueryText  = partitionedQueryExecutionInfo.QueryInfo.RewrittenQuery,
                        Parameters = inputParameters.SqlQuerySpec.Parameters
                    };

                    inputParameters = new InputParameters(
                        rewrittenQuerySpec,
                        inputParameters.InitialUserContinuationToken,
                        inputParameters.InitialFeedRange,
                        inputParameters.MaxConcurrency,
                        inputParameters.MaxItemCount,
                        inputParameters.MaxBufferedItemCount,
                        inputParameters.PartitionKey,
                        inputParameters.Properties,
                        inputParameters.PartitionedQueryExecutionInfo,
                        inputParameters.ExecutionEnvironment,
                        inputParameters.ReturnResultsInDeterministicOrder,
                        inputParameters.ForcePassthrough,
                        inputParameters.TestInjections);
                }

                tryCreateContextTask = CosmosQueryExecutionContextFactory.TryCreateSpecializedDocumentQueryExecutionContextAsync(
                    cosmosQueryContext,
                    inputParameters,
                    partitionedQueryExecutionInfo,
                    targetRanges,
                    containerQueryProperties.ResourceId,
                    cancellationToken);
            }

            return(await tryCreateContextTask);
        }