public override PipelineContinuationTokenTestsOutput ExecuteTest(
            PipelineContinuationTokenTestsInput input)
        {
            TryCatch <CosmosElement> tryParse = CosmosElement.Monadic.Parse(input.ContinuationToken);

            if (tryParse.Failed)
            {
                return(new PipelineContinuationTokenTestsOutputNegative("Failed to parse token."));
            }

            if (!PipelineContinuationToken.TryCreateFromCosmosElement(
                    tryParse.Result,
                    out PipelineContinuationToken pipelineContinuationToken))
            {
                return(new PipelineContinuationTokenTestsOutputNegative("Failed to parse token."));
            }

            if (!PipelineContinuationToken.TryConvertToLatest(
                    pipelineContinuationToken,
                    out PipelineContinuationTokenV1_1 latestPipelineContinuationToken))
            {
                return(new PipelineContinuationTokenTestsOutputNegative("Failed to convert to latest"));
            }

            return(new PipelineContinuationTokenTestsOutputPositive(
                       pipelineContinuationToken,
                       latestPipelineContinuationToken));
        }
 internal PipelineContinuationTokenTestsOutputPositive(
     PipelineContinuationToken parsedToken,
     PipelineContinuationToken latestToken)
 {
     this.ParsedToken = parsedToken;
     this.LatestToken = latestToken;
 }
Exemple #3
0
        public override PipelineContinuationTokenTestsOutput ExecuteTest(
            PipelineContinuationTokenTestsInput input)
        {
            if (!CosmosElement.TryParse(input.ContinuationToken, out CosmosElement cosmosElementContinuationToken))
            {
                return(new PipelineContinuationTokenTestsOutputNegative("Failed to parse token."));
            }

            if (!PipelineContinuationToken.TryCreateFromCosmosElement(
                    cosmosElementContinuationToken,
                    out PipelineContinuationToken pipelineContinuationToken))
            {
                return(new PipelineContinuationTokenTestsOutputNegative("Failed to parse token."));
            }

            if (!PipelineContinuationToken.TryConvertToLatest(
                    pipelineContinuationToken,
                    out PipelineContinuationTokenV1_1 latestPipelineContinuationToken))
            {
                return(new PipelineContinuationTokenTestsOutputNegative("Failed to convert to latest"));
            }

            return(new PipelineContinuationTokenTestsOutputPositive(
                       pipelineContinuationToken,
                       latestPipelineContinuationToken));
        }
Exemple #4
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));
            }
        }
        private static async Task <TryCatch <CosmosQueryExecutionContext> > TryCreateCoreContextAsync(
            CosmosQueryContext cosmosQueryContext,
            InputParameters inputParameters,
            CancellationToken cancellationToken)
        {
            // Try to parse the continuation token.
            string continuationToken = inputParameters.InitialUserContinuationToken;
            PartitionedQueryExecutionInfo queryPlanFromContinuationToken = inputParameters.PartitionedQueryExecutionInfo;

            if (continuationToken != null)
            {
                if (!PipelineContinuationToken.TryParse(
                        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 (queryPlanFromContinuationToken != null)
            {
                partitionedQueryExecutionInfo = queryPlanFromContinuationToken;
            }
            else
            {
                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.QueryClient,
                        inputParameters.SqlQuerySpec,
                        cosmosQueryContext.ResourceLink,
                        inputParameters.PartitionKey,
                        cancellationToken);
                }
                else
                {
                    //todo:elasticcollections this may rely on information from collection cache which is outdated
                    //if collection is deleted/created with same name.
                    //need to make it not rely on information from collection cache.
                    Documents.PartitionKeyDefinition partitionKeyDefinition;
                    if ((inputParameters.Properties != null) &&
                        inputParameters.Properties.TryGetValue(InternalPartitionKeyDefinitionProperty, out object partitionKeyDefinitionObject))
                    {
                        if (partitionKeyDefinitionObject is Documents.PartitionKeyDefinition definition)
                        {
                            partitionKeyDefinition = definition;
                        }
                        else
                        {
                            throw new ArgumentException(
                                      "partitionkeydefinition has invalid type",
                                      nameof(partitionKeyDefinitionObject));
                        }
                    }
                    else
                    {
                        partitionKeyDefinition = containerQueryProperties.PartitionKeyDefinition;
                    }

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

            return(await TryCreateFromPartitionedQuerExecutionInfoAsync(
                       partitionedQueryExecutionInfo,
                       containerQueryProperties,
                       cosmosQueryContext,
                       inputParameters,
                       cancellationToken));
        }
Exemple #6
0
        /// <summary>
        /// Creates a CosmosPipelinedItemQueryExecutionContext.
        /// </summary>
        /// <param name="executionEnvironment">The environment to execute on.</param>
        /// <param name="queryContext">The parameters for constructing the base class.</param>
        /// <param name="initParams">The initial parameters</param>
        /// <param name="requestContinuationToken">The request continuation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task to await on, which in turn returns a CosmosPipelinedItemQueryExecutionContext.</returns>
        public static async Task <CosmosQueryExecutionContext> CreateAsync(
            ExecutionEnvironment executionEnvironment,
            CosmosQueryContext queryContext,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            string requestContinuationToken,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (requestContinuationToken != null)
            {
                if (!PipelineContinuationToken.TryParse(
                        requestContinuationToken,
                        out PipelineContinuationToken pipelineContinuationToken))
                {
                    throw queryContext.QueryClient.CreateBadRequestException(
                              $"Malformed {nameof(PipelineContinuationToken)}: {requestContinuationToken}.");
                }

                if (PipelineContinuationToken.IsTokenFromTheFuture(pipelineContinuationToken))
                {
                    throw queryContext.QueryClient.CreateBadRequestException(
                              $"{nameof(PipelineContinuationToken)} Continuation token is from a newer version of the SDK. Upgrade the SDK to avoid this issue.\n {requestContinuationToken}.");
                }

                if (!PipelineContinuationToken.TryConvertToLatest(
                        pipelineContinuationToken,
                        out PipelineContinuationTokenV1_1 latestVersionPipelineContinuationToken))
                {
                    throw queryContext.QueryClient.CreateBadRequestException(
                              $"{nameof(PipelineContinuationToken)}: '{requestContinuationToken}' is no longer supported.");
                }

                requestContinuationToken = latestVersionPipelineContinuationToken.SourceContinuationToken;
            }

            QueryInfo queryInfo = initParams.PartitionedQueryExecutionInfo.QueryInfo;

            int initialPageSize = initParams.InitialPageSize;

            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams parameters = initParams;
            if (queryInfo.HasGroupBy)
            {
                // The query will block until all groupings are gathered so we might as well speed up the process.
                initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    sqlQuerySpec: initParams.SqlQuerySpec,
                    collectionRid: initParams.CollectionRid,
                    partitionedQueryExecutionInfo: initParams.PartitionedQueryExecutionInfo,
                    partitionKeyRanges: initParams.PartitionKeyRanges,
                    initialPageSize: int.MaxValue,
                    maxConcurrency: initParams.MaxConcurrency,
                    maxItemCount: int.MaxValue,
                    maxBufferedItemCount: initParams.MaxBufferedItemCount);
            }

            Func <string, Task <IDocumentQueryExecutionComponent> > createOrderByComponentFunc = async(continuationToken) =>
            {
                return(await CosmosOrderByItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            Func <string, Task <IDocumentQueryExecutionComponent> > createParallelComponentFunc = async(continuationToken) =>
            {
                return(await CosmosParallelItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            return((CosmosQueryExecutionContext)await PipelinedDocumentQueryExecutionContext.CreateHelperAsync(
                       executionEnvironment,
                       queryContext.QueryClient,
                       initParams.PartitionedQueryExecutionInfo.QueryInfo,
                       initialPageSize,
                       requestContinuationToken,
                       createOrderByComponentFunc,
                       createParallelComponentFunc));
        }