public async Task <FeedResponse <dynamic> > ExecuteNextAsync(CancellationToken token) { if (this.IsDone) { throw new InvalidOperationException(RMResources.DocumentQueryExecutionContextIsDone); } Error error = null; try { return(await this.innerExecutionContext.ExecuteNextAsync(token)); } catch (DocumentClientException ex) { if (ex.StatusCode != HttpStatusCode.BadRequest || ex.GetSubStatus() != SubStatusCodes.CrossPartitionQueryNotServable) { throw; } error = ex.Error; } PartitionedQueryExecutionInfo partitionedQueryExecutionInfo = JsonConvert.DeserializeObject <PartitionedQueryExecutionInfo>(error.AdditionalErrorInfo); DefaultDocumentQueryExecutionContext queryExecutionContext = (DefaultDocumentQueryExecutionContext)this.innerExecutionContext; List <PartitionKeyRange> partitionKeyRanges = await queryExecutionContext.GetTargetPartitionKeyRanges(collection.ResourceId, partitionedQueryExecutionInfo.QueryRanges); this.innerExecutionContext = await DocumentQueryExecutionContextFactory.CreateSpecializedDocumentQueryExecutionContext( this.client, this.resourceTypeEnum, this.resourceType, this.expression, this.feedOptions, this.resourceLink, isContinuationExpected, partitionedQueryExecutionInfo, partitionKeyRanges, this.collection.ResourceId, token, this.correlatedActivityId); return(await this.innerExecutionContext.ExecuteNextAsync(token)); }
/// <summary> /// Gets the list of partition key ranges. /// 1. Check partition key range id /// 2. Check Partition key /// 3. Check the effective partition key /// 4. Get the range from the PartitionedQueryExecutionInfo /// </summary> internal static async Task <List <PartitionKeyRange> > GetTargetPartitionKeyRanges( DefaultDocumentQueryExecutionContext queryExecutionContext, PartitionedQueryExecutionInfo partitionedQueryExecutionInfo, CosmosContainerSettings collection, FeedOptions feedOptions) { List <PartitionKeyRange> targetRanges = null; if (!string.IsNullOrEmpty(feedOptions.PartitionKeyRangeId)) { targetRanges = new List <PartitionKeyRange>() { await queryExecutionContext.GetTargetPartitionKeyRangeById( collection.ResourceId, feedOptions.PartitionKeyRangeId) }; } else if (feedOptions.PartitionKey != null) { targetRanges = await queryExecutionContext.GetTargetPartitionKeyRangesByEpkString( collection.ResourceId, feedOptions.PartitionKey.InternalKey.GetEffectivePartitionKeyString(collection.PartitionKey)); } else if (TryGetEpkProperty(feedOptions, out string effectivePartitionKeyString)) { targetRanges = await queryExecutionContext.GetTargetPartitionKeyRangesByEpkString( collection.ResourceId, effectivePartitionKeyString); } else { targetRanges = await queryExecutionContext.GetTargetPartitionKeyRanges( collection.ResourceId, partitionedQueryExecutionInfo.QueryRanges); } return(targetRanges); }
public static async Task <IDocumentQueryExecutionContext> CreateDocumentQueryExecutionContextAsync( IDocumentQueryClient client, ResourceType resourceTypeEnum, Type resourceType, Expression expression, FeedOptions feedOptions, string resourceLink, bool isContinuationExpected, CancellationToken token, Guid correlatedActivityId) { DocumentQueryExecutionContextBase.InitParams constructorParams = new DocumentQueryExecutionContextBase.InitParams( client, resourceTypeEnum, resourceType, expression, feedOptions, resourceLink, false, correlatedActivityId); CosmosContainerSettings collection = null; if (resourceTypeEnum.IsCollectionChild()) { CollectionCache collectionCache = await client.GetCollectionCacheAsync(); using ( DocumentServiceRequest request = DocumentServiceRequest.Create( OperationType.Query, resourceTypeEnum, resourceLink, AuthorizationTokenType.Invalid)) //this request doesnt actually go to server { collection = await collectionCache.ResolveCollectionAsync(request, token); } } // 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 if (CustomTypeExtensions.ByPassQueryParsing()) { // We create a ProxyDocumentQueryExecutionContext that will be initialized with DefaultDocumentQueryExecutionContext // which will be used to send the query to Gateway and on getting 400(bad request) with 1004(cross partition query not servable), we initialize it with // PipelinedDocumentQueryExecutionContext by providing the partition query execution info that's needed(which we get from the exception returned from Gateway). ProxyDocumentQueryExecutionContext proxyQueryExecutionContext = ProxyDocumentQueryExecutionContext.CreateAsync( client, resourceTypeEnum, resourceType, expression, feedOptions, resourceLink, token, collection, isContinuationExpected, correlatedActivityId); return(proxyQueryExecutionContext); } DefaultDocumentQueryExecutionContext queryExecutionContext = await DefaultDocumentQueryExecutionContext.CreateAsync( constructorParams, isContinuationExpected, token); // If isContinuationExpected is false, we want to check if there are aggregates. if ( resourceTypeEnum.IsCollectionChild() && resourceTypeEnum.IsPartitioned() && (feedOptions.EnableCrossPartitionQuery || !isContinuationExpected)) { //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. PartitionedQueryExecutionInfo partitionedQueryExecutionInfo = await queryExecutionContext.GetPartitionedQueryExecutionInfoAsync( collection.PartitionKey, true, isContinuationExpected, token); if (DocumentQueryExecutionContextFactory.ShouldCreateSpecializedDocumentQueryExecutionContext( resourceTypeEnum, feedOptions, partitionedQueryExecutionInfo, collection.PartitionKey, isContinuationExpected)) { List <PartitionKeyRange> targetRanges; if (!string.IsNullOrEmpty(feedOptions.PartitionKeyRangeId)) { targetRanges = new List <PartitionKeyRange> { await queryExecutionContext.GetTargetPartitionKeyRangeById( collection.ResourceId, feedOptions.PartitionKeyRangeId) }; } else { List <Range <string> > queryRanges = partitionedQueryExecutionInfo.QueryRanges; if (feedOptions.PartitionKey != null) { queryRanges = new List <Range <string> > { Range <string> .GetPointRange( feedOptions.PartitionKey.InternalKey.GetEffectivePartitionKeyString( collection.PartitionKey)) }; } targetRanges = await queryExecutionContext.GetTargetPartitionKeyRanges(collection.ResourceId, queryRanges); } return(await CreateSpecializedDocumentQueryExecutionContext( constructorParams, partitionedQueryExecutionInfo, targetRanges, collection.ResourceId, isContinuationExpected, token)); } } return(queryExecutionContext); }