From 93bb10b47b6bc96b3b647daf84cccb0e850ca9f9 Mon Sep 17 00:00:00 2001 From: Matias Quaranta Date: Wed, 1 Mar 2023 13:06:30 -0800 Subject: [PATCH] ReadMany: Fixes BadRequest when using Ids with single quotes (#3732) * Use parameters * Emulator tests --- .../src/ReadManyQueryHelper.cs | 8 +++-- .../CosmosReadManyItemsTests.cs | 31 ++++++++----------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/ReadManyQueryHelper.cs b/Microsoft.Azure.Cosmos/src/ReadManyQueryHelper.cs index e69476129c..6ebcda267c 100644 --- a/Microsoft.Azure.Cosmos/src/ReadManyQueryHelper.cs +++ b/Microsoft.Azure.Cosmos/src/ReadManyQueryHelper.cs @@ -249,10 +249,13 @@ private QueryDefinition CreateReadManyQueryDefinitionForId(List<(string, Partiti { int totalItemCount = Math.Min(items.Count, startIndex + this.maxItemsPerQuery); StringBuilder queryStringBuilder = new StringBuilder(); + SqlParameterCollection sqlParameters = new SqlParameterCollection(); queryStringBuilder.Append("SELECT * FROM c WHERE c.id IN ( "); for (int i = startIndex; i < totalItemCount; i++) { - queryStringBuilder.Append($"'{items[i].Item1}'"); + string idParamName = "@param_id" + i; + sqlParameters.Add(new SqlParameter(idParamName, items[i].Item1)); + queryStringBuilder.Append(idParamName); if (i < totalItemCount - 1) { queryStringBuilder.Append(","); @@ -260,7 +263,8 @@ private QueryDefinition CreateReadManyQueryDefinitionForId(List<(string, Partiti } queryStringBuilder.Append(" )"); - return new QueryDefinition(queryStringBuilder.ToString()); + return QueryDefinition.CreateFromQuerySpec(new SqlQuerySpec(queryStringBuilder.ToString(), + sqlParameters)); } private QueryDefinition CreateReadManyQueryDefinitionForOther(List<(string, PartitionKey)> items, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosReadManyItemsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosReadManyItemsTests.cs index ede534cb9d..c3949d763f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosReadManyItemsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosReadManyItemsTests.cs @@ -5,16 +5,11 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests { using System; - using System.Collections.Concurrent; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Net; - using System.Net.Http; - using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Fluent; - using Microsoft.Azure.Cosmos.Query.Core; using Microsoft.Azure.Cosmos.Tracing; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -22,16 +17,15 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests public class CosmosReadManyItemsTests : BaseCosmosClientHelper { private Container Container = null; - private ContainerProperties containerSettings = null; [TestInitialize] public async Task TestInitialize() { await base.TestInit(); string PartitionKey = "/pk"; - this.containerSettings = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: PartitionKey); + ContainerProperties containerSettings = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: PartitionKey); ContainerResponse response = await this.database.CreateContainerAsync( - this.containerSettings, + containerSettings, throughput: 20000, cancellationToken: this.cancellationToken); Assert.IsNotNull(response); @@ -122,23 +116,24 @@ public async Task ReadManyDoesNotFetchQueryPlan() [TestMethod] public async Task ReadManyWithIdasPk() { - string PartitionKey = "/id"; - ContainerProperties containerSettings = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: PartitionKey); - Container container = await this.database.CreateContainerAsync(containerSettings); + Container container = await this.database.CreateContainerAsync(Guid.NewGuid().ToString(), "/id"); List<(string, PartitionKey)> itemList = new List<(string, PartitionKey)>(); - for (int i = 0; i < 5; i++) - { - itemList.Add((i.ToString(), new PartitionKey(i.ToString()))); - } // Create items with different pk values for (int i = 0; i < 5; i++) { ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(); - item.id = i.ToString(); ItemResponse itemResponse = await container.CreateItemAsync(item); Assert.AreEqual(HttpStatusCode.Created, itemResponse.StatusCode); + + itemList.Add((item.id, new PartitionKey(item.id))); + + ToDoActivity itemWithSingleQuotes = ToDoActivity.CreateRandomToDoActivity(id: item.id + "'singlequote"); + ItemResponse itemResponseWithSingleQuotes = await container.CreateItemAsync(itemWithSingleQuotes); + Assert.AreEqual(HttpStatusCode.Created, itemResponseWithSingleQuotes.StatusCode); + + itemList.Add((itemWithSingleQuotes.id, new PartitionKey(itemWithSingleQuotes.id))); } using (ResponseMessage responseMessage = await container.ReadManyItemsStreamAsync(itemList)) @@ -149,12 +144,12 @@ public async Task ReadManyWithIdasPk() ToDoActivity[] items = this.GetClient().ClientContext.SerializerCore.FromFeedStream( CosmosFeedResponseSerializer.GetStreamWithoutServiceEnvelope(responseMessage.Content)); - Assert.AreEqual(items.Length, 5); + Assert.AreEqual(items.Length, 10); } FeedResponse feedResponse = await container.ReadManyItemsAsync(itemList); Assert.IsNotNull(feedResponse); - Assert.AreEqual(feedResponse.Count, 5); + Assert.AreEqual(feedResponse.Count, 10); Assert.IsTrue(feedResponse.Headers.RequestCharge > 0); Assert.IsNotNull(feedResponse.Diagnostics); }