public async Task <TryCatch <PartitionedQueryExecutionInfo> > TryGetQueryPlanAsync( SqlQuerySpec sqlQuerySpec, PartitionKeyDefinition partitionKeyDefinition, QueryFeatures supportedQueryFeatures, bool hasLogicalPartitionKey, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (sqlQuerySpec == null) { throw new ArgumentNullException($"{nameof(sqlQuerySpec)}"); } if (partitionKeyDefinition == null) { throw new ArgumentNullException($"{nameof(partitionKeyDefinition)}"); } TryCatch <PartitionedQueryExecutionInfo> tryGetQueryInfo = await this.TryGetQueryInfoAsync( sqlQuerySpec, partitionKeyDefinition, hasLogicalPartitionKey, cancellationToken); if (!tryGetQueryInfo.Succeeded) { return(tryGetQueryInfo); } if (QueryPlanExceptionFactory.TryGetUnsupportedException( tryGetQueryInfo.Result.QueryInfo, supportedQueryFeatures, out Exception queryPlanHandlerException)) { return(TryCatch <PartitionedQueryExecutionInfo> .FromException(queryPlanHandlerException)); } return(tryGetQueryInfo); }
private static void AddExceptionsForAggregateQueries( QueryInfo queryInfo, QueryFeatures supportedQueryFeatures, Lazy <List <Exception> > exceptions) { if (queryInfo.HasAggregates) { bool isSingleAggregate = (queryInfo.Aggregates.Length == 1) || (queryInfo.GroupByAliasToAggregateType.Values.Where(aggregateOperator => aggregateOperator.HasValue).Count() == 1); if (isSingleAggregate) { if (queryInfo.HasSelectValue) { if (!supportedQueryFeatures.HasFlag(QueryFeatures.Aggregate)) { exceptions.Value.Add(QueryContainsUnsupportedAggregates); } } else { if (!supportedQueryFeatures.HasFlag(QueryFeatures.NonValueAggregate)) { exceptions.Value.Add(QueryContainsUnsupportedNonValueAggregate); } } } else { if (!supportedQueryFeatures.HasFlag(QueryFeatures.NonValueAggregate)) { exceptions.Value.Add(QueryContainsUnsupportedNonValueAggregate); } if (!supportedQueryFeatures.HasFlag(QueryFeatures.MultipleAggregates)) { exceptions.Value.Add(QueryContainsUnsupportedMultipleAggregates); } } } }
/// <summary> /// Used in the compute gateway to support legacy gateways query execution pattern. /// </summary> public async Task <TryCatch <(PartitionedQueryExecutionInfo queryPlan, bool supported)> > TryGetQueryInfoAndIfSupportedAsync( QueryFeatures supportedQueryFeatures, SqlQuerySpec sqlQuerySpec, Documents.ResourceType resourceType, PartitionKeyDefinition partitionKeyDefinition, bool hasLogicalPartitionKey, bool useSystemPrefix, CancellationToken cancellationToken = default) { if (sqlQuerySpec == null) { throw new ArgumentNullException(nameof(sqlQuerySpec)); } if (partitionKeyDefinition == null) { throw new ArgumentNullException(nameof(partitionKeyDefinition)); } cancellationToken.ThrowIfCancellationRequested(); TryCatch <PartitionedQueryExecutionInfo> tryGetQueryInfo = await this.TryGetQueryInfoAsync( sqlQuerySpec, resourceType, partitionKeyDefinition, hasLogicalPartitionKey, useSystemPrefix, cancellationToken); if (tryGetQueryInfo.Failed) { return(TryCatch <(PartitionedQueryExecutionInfo, bool)> .FromException(tryGetQueryInfo.Exception)); } QueryFeatures neededQueryFeatures = QueryPlanSupportChecker.GetNeededQueryFeatures( tryGetQueryInfo.Result.QueryInfo, supportedQueryFeatures); return(TryCatch <(PartitionedQueryExecutionInfo, bool)> .FromResult((tryGetQueryInfo.Result, neededQueryFeatures == QueryFeatures.None))); }
private static void AddExceptionsForOrderByQueries( QueryInfo queryInfo, QueryFeatures supportedQueryFeatures, Lazy <List <Exception> > exceptions) { if (queryInfo.HasOrderBy) { if (queryInfo.OrderByExpressions.Length == 1) { if (!supportedQueryFeatures.HasFlag(QueryFeatures.OrderBy)) { exceptions.Value.Add(QueryContainsUnsupportedOrderBy); } } else { if (!supportedQueryFeatures.HasFlag(QueryFeatures.MultipleOrderBy)) { exceptions.Value.Add(QueryContainsUnsupportedMultipleOrderBy); } } } }
public static void ThrowIfNotSupported( QueryInfo queryInfo, QueryFeatures supportedQueryFeatures) { QueryFeatures neededQueryFeatures = QueryPlanSupportChecker.GetNeededQueryFeatures( queryInfo, supportedQueryFeatures); if (neededQueryFeatures != QueryFeatures.None) { List <Exception> queryPlanHandlerExceptions = new List <Exception>(); foreach (QueryFeatures queryFeature in QueryPlanExceptionFactory.QueryFeatureList) { if ((neededQueryFeatures & queryFeature) == queryFeature) { Exception unsupportedFeatureException = QueryPlanExceptionFactory.FeatureToUnsupportedException[queryFeature]; queryPlanHandlerExceptions.Add(unsupportedFeatureException); } } throw new QueryPlanHandlerException(queryPlanHandlerExceptions); } }
/// <summary> /// Used in the compute gateway to support legacy gateways query execution pattern. /// </summary> public async Task <((Exception, PartitionedQueryExecutionInfo), bool)> TryGetQueryInfoAndIfSupportedAsync( QueryFeatures supportedQueryFeatures, SqlQuerySpec sqlQuerySpec, PartitionKeyDefinition partitionKeyDefinition, bool hasLogicalPartitionKey, CancellationToken cancellationToken = default) { if (sqlQuerySpec == null) { throw new ArgumentNullException(nameof(sqlQuerySpec)); } if (partitionKeyDefinition == null) { throw new ArgumentNullException(nameof(partitionKeyDefinition)); } cancellationToken.ThrowIfCancellationRequested(); TryCatch <PartitionedQueryExecutionInfo> tryGetQueryInfo = await this.TryGetQueryInfoAsync( sqlQuerySpec, partitionKeyDefinition, hasLogicalPartitionKey, cancellationToken); if (!tryGetQueryInfo.Succeeded) { // Failed to get QueryInfo, so vacously not supported. return((tryGetQueryInfo.Exception, null), false); } QueryFeatures neededQueryFeatures = QueryPlanSupportChecker.GetNeededQueryFeatures( tryGetQueryInfo.Result.QueryInfo, supportedQueryFeatures); return((null, tryGetQueryInfo.Result), neededQueryFeatures == QueryFeatures.None); }
public static void ThrowIfNotSupported( QueryInfo queryInfo, QueryFeatures supportedQueryFeatures) { Lazy <List <Exception> > exceptions = new Lazy <List <Exception> >(() => { return(new List <Exception>()); }); QueryPlanExceptionFactory.AddExceptionsForAggregateQueries( queryInfo, supportedQueryFeatures, exceptions); QueryPlanExceptionFactory.AddExceptionsForDistinctQueries( queryInfo, supportedQueryFeatures, exceptions); QueryPlanExceptionFactory.AddExceptionsForTopQueries( queryInfo, supportedQueryFeatures, exceptions); QueryPlanExceptionFactory.AddExceptionsForOrderByQueries( queryInfo, supportedQueryFeatures, exceptions); QueryPlanExceptionFactory.AddExceptionsForOffsetLimitQueries( queryInfo, supportedQueryFeatures, exceptions); if (exceptions.IsValueCreated) { throw new QueryPlanHandlerException(exceptions.Value); } }
/// <summary> /// Used in the compute gateway to support legacy gateway interface. /// </summary> public override async Task <TryExecuteQueryResult> TryExecuteQueryAsync( QueryFeatures supportedQueryFeatures, QueryDefinition queryDefinition, string continuationToken, FeedRangeInternal feedRangeInternal, QueryRequestOptions requestOptions, CancellationToken cancellationToken = default(CancellationToken)) { if (queryDefinition == null) { throw new ArgumentNullException(nameof(queryDefinition)); } if (requestOptions == null) { throw new ArgumentNullException(nameof(requestOptions)); } if (feedRangeInternal != null) { // The user has scoped down to a physical partition or logical partition. // In either case let the query execute as a passthrough. QueryIterator passthroughQueryIterator = QueryIterator.Create( client: this.queryClient, clientContext: this.ClientContext, sqlQuerySpec: queryDefinition.ToSqlQuerySpec(), continuationToken: continuationToken, feedRangeInternal: feedRangeInternal, queryRequestOptions: requestOptions, resourceLink: this.LinkUri, isContinuationExpected: false, allowNonValueAggregateQuery: true, forcePassthrough: true, // Forcing a passthrough, since we don't want to get the query plan nor try to rewrite it. partitionedQueryExecutionInfo: null); return(new QueryPlanIsSupportedResult(passthroughQueryIterator)); } cancellationToken.ThrowIfCancellationRequested(); Documents.PartitionKeyDefinition partitionKeyDefinition; if (requestOptions.Properties != null && requestOptions.Properties.TryGetValue("x-ms-query-partitionkey-definition", out object partitionKeyDefinitionObject)) { if (partitionKeyDefinitionObject is Documents.PartitionKeyDefinition definition) { partitionKeyDefinition = definition; } else { throw new ArgumentException( "partitionkeydefinition has invalid type", nameof(partitionKeyDefinitionObject)); } } else { ContainerQueryProperties containerQueryProperties = await this.queryClient.GetCachedContainerQueryPropertiesAsync( this.LinkUri, requestOptions.PartitionKey, cancellationToken); partitionKeyDefinition = containerQueryProperties.PartitionKeyDefinition; } QueryPlanHandler queryPlanHandler = new QueryPlanHandler(this.queryClient); TryCatch <(PartitionedQueryExecutionInfo queryPlan, bool supported)> tryGetQueryInfoAndIfSupported = await queryPlanHandler.TryGetQueryInfoAndIfSupportedAsync( supportedQueryFeatures, queryDefinition.ToSqlQuerySpec(), partitionKeyDefinition, requestOptions.PartitionKey.HasValue, cancellationToken); if (tryGetQueryInfoAndIfSupported.Failed) { return(new FailedToGetQueryPlanResult(tryGetQueryInfoAndIfSupported.Exception)); } (PartitionedQueryExecutionInfo queryPlan, bool supported) = tryGetQueryInfoAndIfSupported.Result; TryExecuteQueryResult tryExecuteQueryResult; if (supported) { QueryIterator queryIterator = QueryIterator.Create( client: this.queryClient, clientContext: this.ClientContext, sqlQuerySpec: queryDefinition.ToSqlQuerySpec(), continuationToken: continuationToken, feedRangeInternal: feedRangeInternal, queryRequestOptions: requestOptions, resourceLink: this.LinkUri, isContinuationExpected: false, allowNonValueAggregateQuery: true, forcePassthrough: false, partitionedQueryExecutionInfo: queryPlan); tryExecuteQueryResult = new QueryPlanIsSupportedResult(queryIterator); } else { tryExecuteQueryResult = new QueryPlanNotSupportedResult(queryPlan); } return(tryExecuteQueryResult); }
/// <summary> /// Used in the compute gateway to support legacy gateway interface. /// </summary> internal async Task <((Exception, PartitionedQueryExecutionInfo), (bool, QueryIterator))> TryExecuteQueryAsync( QueryFeatures supportedQueryFeatures, QueryDefinition queryDefinition, string continuationToken, QueryRequestOptions requestOptions, CancellationToken cancellationToken = default(CancellationToken)) { if (queryDefinition == null) { throw new ArgumentNullException(nameof(queryDefinition)); } if (requestOptions == null) { throw new ArgumentNullException(nameof(requestOptions)); } cancellationToken.ThrowIfCancellationRequested(); Documents.PartitionKeyDefinition partitionKeyDefinition; if (requestOptions.Properties != null && requestOptions.Properties.TryGetValue("x-ms-query-partitionkey-definition", out object partitionKeyDefinitionObject)) { if (partitionKeyDefinitionObject is Documents.PartitionKeyDefinition definition) { partitionKeyDefinition = definition; } else { throw new ArgumentException( "partitionkeydefinition has invalid type", nameof(partitionKeyDefinitionObject)); } } else { ContainerQueryProperties containerQueryProperties = await this.queryClient.GetCachedContainerQueryPropertiesAsync( this.LinkUri, requestOptions.PartitionKey, cancellationToken); partitionKeyDefinition = containerQueryProperties.PartitionKeyDefinition; } QueryPlanHandler queryPlanHandler = new QueryPlanHandler(this.queryClient); ((Exception exception, PartitionedQueryExecutionInfo partitionedQueryExecutionInfo), bool supported) = await queryPlanHandler.TryGetQueryInfoAndIfSupportedAsync( supportedQueryFeatures, queryDefinition.ToSqlQuerySpec(), partitionKeyDefinition, requestOptions.PartitionKey.HasValue, cancellationToken); if (exception != null) { return((exception, null), (false, null)); } QueryIterator queryIterator; if (supported) { queryIterator = QueryIterator.Create( client: this.queryClient, clientContext: this.ClientContext, sqlQuerySpec: queryDefinition.ToSqlQuerySpec(), continuationToken: continuationToken, queryRequestOptions: requestOptions, resourceLink: this.LinkUri, isContinuationExpected: false, allowNonValueAggregateQuery: true, partitionedQueryExecutionInfo: partitionedQueryExecutionInfo); } else { queryIterator = null; } return((null, partitionedQueryExecutionInfo), (supported, queryIterator)); }
/// <summary> /// Creates a <see cref="NotSupportedException"/> with message that says that <paramref name="feature"/> /// is not supported by current storage. /// </summary> /// <param name="feature">The feature.</param> /// <returns>Created exception.</returns> public static NotSupportedException NotSupported(QueryFeatures feature) { return(NotSupported(feature.ToString())); }
/// <summary> /// Determines whether the specified active features is supported. /// </summary> public static bool Supports(this QueryFeatures available, QueryFeatures required) { return((available & required) == required); }