Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query : Fixes OFFSET, LIMIT, TOP data types to match those coming from query plan #4939

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,33 @@ public static TryCatch<IQueryPipelineStage> MonadicCreate(
maxConcurrency: maxConcurrency);

if (hybridSearchQueryInfo.Skip != null)
{
{
if (hybridSearchQueryInfo.Skip.Value > int.MaxValue)
{
throw new ArgumentOutOfRangeException("skipCount");
}
adityasa marked this conversation as resolved.
Show resolved Hide resolved

adityasa marked this conversation as resolved.
Show resolved Hide resolved
int skipCount = (int)hybridSearchQueryInfo.Skip.Value;

MonadicCreatePipelineStage monadicCreateSourceStage = monadicCreatePipelineStage;
monadicCreatePipelineStage = (continuationToken) => SkipQueryPipelineStage.MonadicCreate(
hybridSearchQueryInfo.Skip.Value,
skipCount,
continuationToken,
monadicCreateSourceStage);
}

if (hybridSearchQueryInfo.Take != null)
{
if (hybridSearchQueryInfo.Take.Value > int.MaxValue)
{
throw new ArgumentOutOfRangeException("takeCount");
}

int takeCount = (int)hybridSearchQueryInfo.Take.Value;

MonadicCreatePipelineStage monadicCreateSourceStage = monadicCreatePipelineStage;
monadicCreatePipelineStage = (continuationToken) => TakeQueryPipelineStage.MonadicCreateLimitStage(
hybridSearchQueryInfo.Take.Value,
takeCount,
requestContinuationToken,
monadicCreateSourceStage);
}
Expand Down Expand Up @@ -150,7 +164,7 @@ public static TryCatch<IQueryPipelineStage> MonadicCreate(
long optimalPageSize = maxItemCount;
if (queryInfo.HasOrderBy)
{
int top;
uint top;
if (queryInfo.HasTop && (queryInfo.Top.Value > 0))
{
top = queryInfo.Top.Value;
Expand All @@ -162,6 +176,11 @@ public static TryCatch<IQueryPipelineStage> MonadicCreate(
else
{
top = 0;
}

if (top > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(queryInfo.Top.Value));
}

if (top > 0)
Expand Down Expand Up @@ -256,28 +275,49 @@ public static TryCatch<IQueryPipelineStage> MonadicCreate(
}

if (queryInfo.HasOffset)
{
{
if (queryInfo.Offset.Value > int.MaxValue)
{
throw new ArgumentOutOfRangeException("offsetCount");
}

int offsetCount = (int)queryInfo.Offset.Value;

MonadicCreatePipelineStage monadicCreateSourceStage = monadicCreatePipelineStage;
monadicCreatePipelineStage = (continuationToken) => SkipQueryPipelineStage.MonadicCreate(
queryInfo.Offset.Value,
offsetCount,
continuationToken,
monadicCreateSourceStage);
}

if (queryInfo.HasLimit)
{
if (queryInfo.Limit.Value > int.MaxValue)
{
throw new ArgumentOutOfRangeException("limitCount");
}

int limitCount = (int)queryInfo.Limit.Value;

MonadicCreatePipelineStage monadicCreateSourceStage = monadicCreatePipelineStage;
monadicCreatePipelineStage = (continuationToken) => TakeQueryPipelineStage.MonadicCreateLimitStage(
queryInfo.Limit.Value,
limitCount,
continuationToken,
monadicCreateSourceStage);
}

if (queryInfo.HasTop)
{
if (queryInfo.Top.Value > int.MaxValue)
{
throw new ArgumentOutOfRangeException("topCount");
}

int topCount = (int)queryInfo.Top.Value;

MonadicCreatePipelineStage monadicCreateSourceStage = monadicCreatePipelineStage;
monadicCreatePipelineStage = (continuationToken) => TakeQueryPipelineStage.MonadicCreateTopStage(
queryInfo.Top.Value,
topCount,
continuationToken,
monadicCreateSourceStage);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
namespace Microsoft.Azure.Cosmos.Query.Core.Pipeline.Skip
{
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -32,7 +33,7 @@ private ClientSkipQueryPipelineStage(
int offsetCount,
CosmosElement continuationToken,
MonadicCreatePipelineStage monadicCreatePipelineStage)
{
{
if (monadicCreatePipelineStage == null)
{
throw new ArgumentNullException(nameof(monadicCreatePipelineStage));
Expand Down Expand Up @@ -120,7 +121,9 @@ public override async ValueTask<bool> MoveNextAsync(ITrace trace, CancellationTo
IReadOnlyList<CosmosElement> documentsAfterSkip = sourcePage.Documents.Skip(this.skipCount).ToList();

int numberOfDocumentsSkipped = sourcePage.Documents.Count - documentsAfterSkip.Count;
this.skipCount -= numberOfDocumentsSkipped;
this.skipCount -= numberOfDocumentsSkipped;

Debug.Assert(this.skipCount >= 0, $"{nameof(SkipQueryPipelineStage)} Assert!", "this.skipCount should be greater than or equal to 0");

QueryState state;
if ((sourcePage.State != null) && (sourcePage.DisallowContinuationTokenMessage == null))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected SkipQueryPipelineStage(
long skipCount)
: base(source)
{
if (skipCount > int.MaxValue)
if (skipCount > int.MaxValue || skipCount < 0)
{
throw new ArgumentOutOfRangeException(nameof(skipCount));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private ClientTakeQueryPipelineStage(
{
if (limitCount < 0)
{
throw new ArgumentException($"{nameof(limitCount)}: {limitCount} must be a non negative number.");
throw new ArgumentException($"{nameof(limitCount)}: {limitCount} must be a non negative number.");
}

if (monadicCreatePipelineStage == null)
Expand Down Expand Up @@ -256,7 +256,7 @@ private sealed class LimitContinuationToken : TakeContinuationToken
/// <param name="limit">The limit to the number of document drained for the remainder of the query.</param>
/// <param name="sourceToken">The continuation token for the source component of the query.</param>
public LimitContinuationToken(int limit, string sourceToken)
{
{
if (limit < 0)
{
throw new ArgumentException($"{nameof(limit)} must be a non negative number.");
Expand Down Expand Up @@ -330,7 +330,7 @@ private sealed class TopContinuationToken : TakeContinuationToken
/// <param name="top">The limit to the number of document drained for the remainder of the query.</param>
/// <param name="sourceToken">The continuation token for the source component of the query.</param>
public TopContinuationToken(int top, string sourceToken)
{
{
this.Top = top;
this.SourceToken = sourceToken;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ protected TakeQueryPipelineStage(
IQueryPipelineStage source,
int takeCount)
: base(source)
{
{
this.takeCount = takeCount;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ public QueryInfo ProjectionQueryInfo
}

[JsonProperty("skip")]
public int? Skip
public uint? Skip
{
get;
set;
}

[JsonProperty("take")]
public int? Take
public uint? Take
{
get;
set;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ public DistinctQueryType DistinctType
}

[JsonProperty("top")]
public int? Top
public uint? Top
{
get;
set;
}

[JsonProperty("offset")]
public int? Offset
public uint? Offset
{
get;
set;
}

[JsonProperty("limit")]
public int? Limit
public uint? Limit
{
get;
set;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,45 @@ await this.CreateIngestQueryDeleteAsync(
QueryTestsBase.NoDocuments,
ImplementationAsync);
}

[TestMethod]
public async Task TestTopOffsetLimitClientRanges()
{
async Task ImplementationAsync(Container container, IReadOnlyList<CosmosObject> documents)
{
await QueryTestsBase.NoOp();

foreach((string parameterName, string query) in new[]
{
("offsetCount", "SELECT c.name FROM c OFFSET 2147483648 LIMIT 10"),
("limitCount", "SELECT c.name FROM c OFFSET 10 LIMIT 2147483648"),
("topCount", "SELECT TOP 2147483648 c.name FROM c"),
})
try
{
List<Document> expectedValues = new List<Document>();
FeedIterator<Document> resultSetIterator = container.GetItemQueryIterator<Document>(
query,
requestOptions: new QueryRequestOptions() { MaxConcurrency = 0 });

while (resultSetIterator.HasMoreResults)
{
expectedValues.AddRange(await resultSetIterator.ReadNextAsync());
}

Assert.Fail("Expected to get an exception for this query.");
}
catch (ArgumentOutOfRangeException e)
{
Assert.IsTrue(e.Message.Contains(parameterName));
}
}

await this.CreateIngestQueryDeleteAsync(
ConnectionModes.Direct | ConnectionModes.Gateway,
CollectionTypes.MultiPartition,
QueryTestsBase.NoDocuments,
ImplementationAsync);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,43 @@ ORDER BY c.guid
}
}
}

[TestMethod]
public async Task TestTopOffsetLimitClientRanges()
{
async Task ImplementationAsync(Container container, IReadOnlyList<CosmosObject> documents)
{
await QueryTestsBase.NoOp();

foreach (string query in new[]
{
"SELECT c.name FROM c OFFSET 0 LIMIT 10",
"SELECT c.name FROM c OFFSET 2147483647 LIMIT 10",
"SELECT c.name FROM c OFFSET 10 LIMIT 0",
"SELECT c.name FROM c OFFSET 10 LIMIT 2147483647",
"SELECT TOP 0 c.name FROM c",
"SELECT TOP 2147483647 c.name FROM c",
})
{
List<CosmosElement> expectedValues = new List<CosmosElement>();
FeedIterator<CosmosElement> resultSetIterator = container.GetItemQueryIterator<CosmosElement>(
query,
requestOptions: new QueryRequestOptions() { MaxConcurrency = 0 });

while (resultSetIterator.HasMoreResults)
{
expectedValues.AddRange(await resultSetIterator.ReadNextAsync());
}

Assert.AreEqual(0, expectedValues.Count);
}
}

await this.CreateIngestQueryDeleteAsync(
ConnectionModes.Direct | ConnectionModes.Gateway,
CollectionTypes.MultiPartition,
QueryTestsBase.NoDocuments,
ImplementationAsync);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
<PartitionKeyType>Hash</PartitionKeyType>
</Input>
<Output>
<Exception>TryCatch resulted in an exception.</Exception>
<Exception>Microsoft.Azure.Cosmos.Query.Core.Monads.ExceptionWithStackTraceException : TryCatch resulted in an exception.
Microsoft.Azure.Cosmos.Query.Core.Exceptions.ExpectedQueryPartitionProviderException : {"Errors":["Compositions of aggregates and other expressions are not allowed."]}
System.Runtime.InteropServices.COMException : 0x800A0B00
</Exception>
</Output>
</Result>
<Result>
Expand All @@ -24,7 +27,10 @@
<PartitionKeyType>Hash</PartitionKeyType>
</Input>
<Output>
<Exception>TryCatch resulted in an exception.</Exception>
<Exception>Microsoft.Azure.Cosmos.Query.Core.Monads.ExceptionWithStackTraceException : TryCatch resulted in an exception.
Microsoft.Azure.Cosmos.Query.Core.Exceptions.ExpectedQueryPartitionProviderException : {"errors":[{"severity":"Error","location":{"start":24,"end":25},"code":"SC2041","message":"'SELECT *' is not allowed with GROUP BY."}]}
System.Runtime.InteropServices.COMException : 0x800A0B00
</Exception>
</Output>
</Result>
<Result>
Expand All @@ -38,7 +44,10 @@
<PartitionKeyType>Hash</PartitionKeyType>
</Input>
<Output>
<Exception>TryCatch resulted in an exception.</Exception>
<Exception>Microsoft.Azure.Cosmos.Query.Core.Monads.ExceptionWithStackTraceException : TryCatch resulted in an exception.
Microsoft.Azure.Cosmos.Query.Core.Exceptions.ExpectedQueryPartitionProviderException : {"errors":[{"severity":"Error","location":{"start":24,"end":25},"code":"SC2041","message":"'SELECT *' is not allowed with GROUP BY."}]}
System.Runtime.InteropServices.COMException : 0x800A0B00
</Exception>
</Output>
</Result>
<Result>
Expand Down Expand Up @@ -467,7 +476,10 @@ GROUP BY UPPER(c.name), SUBSTRING(c.address.city, 0, 3)]]></RewrittenQuery>
<PartitionKeyType>Hash</PartitionKeyType>
</Input>
<Output>
<Exception>TryCatch resulted in an exception.</Exception>
<Exception>Microsoft.Azure.Cosmos.Query.Core.Monads.ExceptionWithStackTraceException : TryCatch resulted in an exception.
Microsoft.Azure.Cosmos.Query.Core.Exceptions.ExpectedQueryPartitionProviderException : {"errors":[{"severity":"Error","location":{"start":32,"end":39},"code":"SC2102","message":"Property reference 's.score' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."},{"severity":"Error","location":{"start":41,"end":49},"code":"SC2102","message":"Property reference 's.repeat' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."}]}
System.Runtime.InteropServices.COMException : 0x800A0B00
</Exception>
</Output>
</Result>
<Result>
Expand Down
Loading