public PartitionedQueryExecutionInfo GetPartitionedQueryExecutionInfo(
            SqlQuerySpec querySpec,
            PartitionKeyDefinition partitionKeyDefinition,
            bool requireFormattableOrderByQuery,
            bool isContinuationExpected)
        {
            PartitionedQueryExecutionInfoInternal queryInfoInternal = this.GetPartitionedQueryExecutionInfoInternal(
                querySpec,
                partitionKeyDefinition,
                requireFormattableOrderByQuery,
                isContinuationExpected);

            return(this.ConvertPartitionedQueryExecutionInfo(queryInfoInternal, partitionKeyDefinition));
        }
        public PartitionedQueryExecutionInfo GetPartitionedQueryExecutionInfo(
            SqlQuerySpec querySpec,
            PartitionKeyDefinition partitionKeyDefinition,
            bool requireFormattableOrderByQuery,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            bool hasLogicalPartitionKey)
        {
            PartitionedQueryExecutionInfoInternal queryInfoInternal = this.GetPartitionedQueryExecutionInfoInternal(
                querySpec,
                partitionKeyDefinition,
                requireFormattableOrderByQuery,
                isContinuationExpected,
                allowNonValueAggregateQuery,
                hasLogicalPartitionKey);

            return(this.ConvertPartitionedQueryExecutionInfo(queryInfoInternal, partitionKeyDefinition));
        }
        internal PartitionedQueryExecutionInfo ConvertPartitionedQueryExecutionInfo(
            PartitionedQueryExecutionInfoInternal queryInfoInternal,
            PartitionKeyDefinition partitionKeyDefinition)
        {
            List <Range <string> > effectiveRanges = new List <Range <string> >(queryInfoInternal.QueryRanges.Count);

            foreach (Range <PartitionKeyInternal> internalRange in queryInfoInternal.QueryRanges)
            {
                effectiveRanges.Add(new Range <string>(
                                        internalRange.Min.GetEffectivePartitionKeyString(partitionKeyDefinition, false),
                                        internalRange.Max.GetEffectivePartitionKeyString(partitionKeyDefinition, false),
                                        internalRange.IsMinInclusive,
                                        internalRange.IsMaxInclusive));
            }

            effectiveRanges.Sort(Range <string> .MinComparer.Instance);

            return(new PartitionedQueryExecutionInfo()
            {
                QueryInfo = queryInfoInternal.QueryInfo,
                QueryRanges = effectiveRanges,
            });
        }
        internal PartitionedQueryExecutionInfoInternal GetPartitionedQueryExecutionInfoInternal(
            SqlQuerySpec querySpec,
            PartitionKeyDefinition partitionKeyDefinition,
            bool requireFormattableOrderByQuery,
            bool isContinuationExpected)
        {
            if (querySpec == null || partitionKeyDefinition == null)
            {
                return(DefaultInfoInternal);
            }

            string queryText = JsonConvert.SerializeObject(querySpec);

            List <string> paths = new List <string>(partitionKeyDefinition.Paths);

            List <string[]> pathParts = new List <string[]>();

            paths.ForEach(path =>
            {
                pathParts.Add(PathParser.GetPathParts(path).ToArray());
            });

            string[] allParts     = pathParts.SelectMany(parts => parts).ToArray();
            uint[]   partsLengths = pathParts.Select(parts => (uint)parts.Length).ToArray();

            PartitionKind partitionKind = partitionKeyDefinition.Kind;

            this.Initialize();

            byte[] buffer = new byte[InitialBufferSize];
            uint   errorCode;
            uint   serializedQueryExecutionInfoResultLength;

            unsafe
            {
                fixed(byte *bytePtr = buffer)
                {
                    errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery(
                        this.serviceProvider,
                        queryText,
                        requireFormattableOrderByQuery,
                        isContinuationExpected,
                        allParts,
                        partsLengths,
                        (uint)partitionKeyDefinition.Paths.Count,
                        partitionKind,
                        new IntPtr(bytePtr),
                        (uint)buffer.Length,
                        out serializedQueryExecutionInfoResultLength);

                    if (errorCode == DISP_E_BUFFERTOOSMALL)
                    {
                        buffer = new byte[serializedQueryExecutionInfoResultLength];
                        fixed(byte *bytePtr2 = buffer)
                        {
                            errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery(
                                this.serviceProvider,
                                queryText,
                                requireFormattableOrderByQuery,
                                isContinuationExpected,
                                allParts,
                                partsLengths,
                                (uint)partitionKeyDefinition.Paths.Count,
                                partitionKind,
                                new IntPtr(bytePtr2),
                                (uint)buffer.Length,
                                out serializedQueryExecutionInfoResultLength);
                        }
                    }
                }
            }

            string serializedQueryExecutionInfo = Encoding.UTF8.GetString(buffer, 0, (int)serializedQueryExecutionInfoResultLength);

            Exception exception = Marshal.GetExceptionForHR((int)errorCode);

            if (exception != null)
            {
                DefaultTrace.TraceInformation("QueryEngineConfiguration: " + this.queryengineConfiguration);
                throw new BadRequestException(
                          "Message: " + serializedQueryExecutionInfo,
                          exception);
            }

            PartitionedQueryExecutionInfoInternal queryInfoInternal =
                JsonConvert.DeserializeObject <PartitionedQueryExecutionInfoInternal>(
                    serializedQueryExecutionInfo,
                    new JsonSerializerSettings {
                DateParseHandling = DateParseHandling.None
            });

            return(queryInfoInternal);
        }
        internal TryCatch <PartitionedQueryExecutionInfoInternal> TryGetPartitionedQueryExecutionInfoInternal(
            SqlQuerySpec querySpec,
            PartitionKeyDefinition partitionKeyDefinition,
            bool requireFormattableOrderByQuery,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            bool hasLogicalPartitionKey)
        {
            if (querySpec == null || partitionKeyDefinition == null)
            {
                return(TryCatch <PartitionedQueryExecutionInfoInternal> .FromResult(DefaultInfoInternal));
            }

            string queryText = JsonConvert.SerializeObject(querySpec);

            List <string> paths = new List <string>(partitionKeyDefinition.Paths);

            List <string[]> pathParts = new List <string[]>();

            paths.ForEach(path =>
            {
                pathParts.Add(PathParser.GetPathParts(path));
            });

            string[] allParts     = pathParts.SelectMany(parts => parts).ToArray();
            uint[]   partsLengths = pathParts.Select(parts => (uint)parts.Length).ToArray();

            PartitionKind partitionKind = partitionKeyDefinition.Kind;

            this.Initialize();

            byte[] buffer = new byte[InitialBufferSize];
            uint   errorCode;
            uint   serializedQueryExecutionInfoResultLength;

            unsafe
            {
                fixed(byte *bytePtr = buffer)
                {
                    errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery(
                        this.serviceProvider,
                        queryText,
                        requireFormattableOrderByQuery,
                        isContinuationExpected,
                        allowNonValueAggregateQuery,
                        hasLogicalPartitionKey,
                        allParts,
                        partsLengths,
                        (uint)partitionKeyDefinition.Paths.Count,
                        partitionKind,
                        new IntPtr(bytePtr),
                        (uint)buffer.Length,
                        out serializedQueryExecutionInfoResultLength);

                    if (errorCode == DISP_E_BUFFERTOOSMALL)
                    {
                        buffer = new byte[serializedQueryExecutionInfoResultLength];
                        fixed(byte *bytePtr2 = buffer)
                        {
                            errorCode = ServiceInteropWrapper.GetPartitionKeyRangesFromQuery(
                                this.serviceProvider,
                                queryText,
                                requireFormattableOrderByQuery,
                                isContinuationExpected,
                                allowNonValueAggregateQuery,
                                hasLogicalPartitionKey, // has logical partition key
                                allParts,
                                partsLengths,
                                (uint)partitionKeyDefinition.Paths.Count,
                                partitionKind,
                                new IntPtr(bytePtr2),
                                (uint)buffer.Length,
                                out serializedQueryExecutionInfoResultLength);
                        }
                    }
                }
            }

            string serializedQueryExecutionInfo = Encoding.UTF8.GetString(buffer, 0, (int)serializedQueryExecutionInfoResultLength);

            Exception exception = Marshal.GetExceptionForHR((int)errorCode);

            if (exception != null)
            {
                QueryPartitionProviderException queryPartitionProviderException;
                if (string.IsNullOrEmpty(serializedQueryExecutionInfo))
                {
                    queryPartitionProviderException = new UnexpectedQueryPartitionProviderException(
                        "Query service interop parsing hit an unexpected exception",
                        exception);
                }
                else
                {
                    queryPartitionProviderException = new ExpectedQueryPartitionProviderException(
                        serializedQueryExecutionInfo,
                        exception);
                }

                return(TryCatch <PartitionedQueryExecutionInfoInternal> .FromException(
                           queryPartitionProviderException));
            }

            PartitionedQueryExecutionInfoInternal queryInfoInternal =
                JsonConvert.DeserializeObject <PartitionedQueryExecutionInfoInternal>(
                    serializedQueryExecutionInfo,
                    new JsonSerializerSettings
            {
                DateParseHandling = DateParseHandling.None
            });

            return(TryCatch <PartitionedQueryExecutionInfoInternal> .FromResult(queryInfoInternal));
        }