diff --git a/sdk/tables/Azure.Data.Tables/CHANGELOG.md b/sdk/tables/Azure.Data.Tables/CHANGELOG.md
index a7f7638829dc..4e0552458bdf 100644
--- a/sdk/tables/Azure.Data.Tables/CHANGELOG.md
+++ b/sdk/tables/Azure.Data.Tables/CHANGELOG.md
@@ -1,14 +1,17 @@
# Release History
-## 12.10.0-beta.1 (Unreleased)
-
-### Features Added
+## 12.10.0 (2025-01-14)
### Breaking Changes
-- Calling `TableClient.Query`, `TableClient.QueryAsync`, or `TableClient.CreateQueryFilter` with a filter expression that uses `string.Equals` or `string.Compare` with a `StringComparison` parameter will now throw an exception. This is because the Azure Table service does not support these methods in query filters. Previously the `StringComparison` argument was silently ignored, which can lead to subtle bugs in client code.
+- Calling `TableClient.Query`, `TableClient.QueryAsync`, or `TableClient.CreateQueryFilter` with a filter expression that uses `string.Equals` or `string.Compare` with a `StringComparison` parameter will now throw an exception. This is because the Azure Table service does not support these methods in query filters. Previously the `StringComparison` argument was silently ignored, which can lead to subtle bugs in client code. The new behavior can be overridden by either setting an AppContext switch named "Azure.Data.Tables.DisableThrowOnStringComparisonFilter" to `true` or by setting the environment variable "AZURE_DATA_TABLES_DISABLE_THROWONSTRINGCOMPARISONFILTER" to "true". Note: AppContext switches can also be configured via configuration like below:
+
+```xml
+
+
+
+ ```
-### Bugs Fixed
### Other Changes
- Improved the performance of `TableServiceClient.GetTableClient()`
diff --git a/sdk/tables/Azure.Data.Tables/src/Azure.Data.Tables.csproj b/sdk/tables/Azure.Data.Tables/src/Azure.Data.Tables.csproj
index 608c3c3cfcb8..d561f9c1a6ad 100644
--- a/sdk/tables/Azure.Data.Tables/src/Azure.Data.Tables.csproj
+++ b/sdk/tables/Azure.Data.Tables/src/Azure.Data.Tables.csproj
@@ -2,7 +2,7 @@
This client library enables working with the Microsoft Azure Table service
Microsoft Azure.Data.Tables client library
- 12.10.0-beta.1
+ 12.10.0
12.9.1
TableSDK;$(DefineConstants)
diff --git a/sdk/tables/Azure.Data.Tables/src/Queryable/ExpressionNormalizer.cs b/sdk/tables/Azure.Data.Tables/src/Queryable/ExpressionNormalizer.cs
index 1bfe6237cd08..e9cf61276ae2 100644
--- a/sdk/tables/Azure.Data.Tables/src/Queryable/ExpressionNormalizer.cs
+++ b/sdk/tables/Azure.Data.Tables/src/Queryable/ExpressionNormalizer.cs
@@ -162,7 +162,7 @@ internal Expression VisitMethodCallNoRewrite(MethodCallExpression call)
if (visited.Method.IsStatic && visited.Method.Name == "Equals" && visited.Arguments.Count > 1)
{
- if (visited.Arguments.Count > 2)
+ if (visited.Arguments.Count > 2 && !TablesCompatSwitches.DisableThrowOnStringComparisonFilter)
{
throw new NotSupportedException("string.Equals method with more than two arguments is not supported.");
}
@@ -171,7 +171,7 @@ internal Expression VisitMethodCallNoRewrite(MethodCallExpression call)
if (!visited.Method.IsStatic && visited.Method.Name == "Equals" && visited.Arguments.Count > 0)
{
- if (visited.Arguments.Count > 1)
+ if (visited.Arguments.Count > 1 && !TablesCompatSwitches.DisableThrowOnStringComparisonFilter)
{
throw new NotSupportedException("Equals method with more than two arguments is not supported.");
}
@@ -190,7 +190,7 @@ internal Expression VisitMethodCallNoRewrite(MethodCallExpression call)
if (visited.Method.IsStatic && visited.Method.Name == "Compare" && visited.Arguments.Count > 1 && visited.Method.ReturnType == typeof(int))
{
- if (visited.Arguments.Count > 2)
+ if (visited.Arguments.Count > 2 && !TablesCompatSwitches.DisableThrowOnStringComparisonFilter)
{
throw new NotSupportedException("string.Compare method with more than two arguments is not supported.");
}
diff --git a/sdk/tables/Azure.Data.Tables/src/TableConstants.cs b/sdk/tables/Azure.Data.Tables/src/TableConstants.cs
index 91f847232b8c..857bfb266efb 100644
--- a/sdk/tables/Azure.Data.Tables/src/TableConstants.cs
+++ b/sdk/tables/Azure.Data.Tables/src/TableConstants.cs
@@ -17,6 +17,8 @@ internal static class CompatSwitches
public const string DisableEscapeSingleQuotesOnGetEntityEnvVar = "AZURE_DATA_TABLES_DISABLE_ESCAPESINGLEQUOTESONGETENTITY";
public const string DisableEscapeSingleQuotesOnDeleteEntitySwitchName = "Azure.Data.Tables.DisableEscapeSingleQuotesOnDeleteEntity";
public const string DisableEscapeSingleQuotesOnDeleteEntityEnvVar = "AZURE_DATA_TABLES_DISABLE_ESCAPESINGLEQUOTESONDELETEENTITY";
+ public const string DisableThrowOnStringComparisonFilterSwitchName = "Azure.Data.Tables.DisableThrowOnStringComparisonFilter";
+ public const string DisableThrowOnStringComparisonFilterEnvVar = "AZURE_DATA_TABLES_DISABLE_THROWONSTRINGCOMPARISONFILTER";
}
internal static class HeaderNames
diff --git a/sdk/tables/Azure.Data.Tables/src/TablesCompatSwitches.cs b/sdk/tables/Azure.Data.Tables/src/TablesCompatSwitches.cs
index 8994bb8123a3..fb232b7a1ede 100644
--- a/sdk/tables/Azure.Data.Tables/src/TablesCompatSwitches.cs
+++ b/sdk/tables/Azure.Data.Tables/src/TablesCompatSwitches.cs
@@ -16,5 +16,10 @@ public static bool DisableEscapeSingleQuotesOnDeleteEntity
=> AppContextSwitchHelper.GetConfigValue(
TableConstants.CompatSwitches.DisableEscapeSingleQuotesOnDeleteEntitySwitchName,
TableConstants.CompatSwitches.DisableEscapeSingleQuotesOnDeleteEntityEnvVar);
+
+ public static bool DisableThrowOnStringComparisonFilter
+ => AppContextSwitchHelper.GetConfigValue(
+ TableConstants.CompatSwitches.DisableThrowOnStringComparisonFilterSwitchName,
+ TableConstants.CompatSwitches.DisableThrowOnStringComparisonFilterEnvVar);
}
}
diff --git a/sdk/tables/Azure.Data.Tables/tests/TableClientQueryExpressionTests.cs b/sdk/tables/Azure.Data.Tables/tests/TableClientQueryExpressionTests.cs
index d3799dc0571e..8eb213edd6b1 100644
--- a/sdk/tables/Azure.Data.Tables/tests/TableClientQueryExpressionTests.cs
+++ b/sdk/tables/Azure.Data.Tables/tests/TableClientQueryExpressionTests.cs
@@ -5,6 +5,7 @@
using System.Linq;
using System.Linq.Expressions;
using System.Xml;
+using Azure.Core.TestFramework;
using Azure.Data.Tables.Models;
using NUnit.Framework;
using static Azure.Data.Tables.Tests.TableServiceLiveTestsBase;
@@ -176,7 +177,7 @@ public class TableClientQueryExpressionTests
new object[] { $"PartitionKey eq '{Partition}'", s_tableEntExpEquals },
};
- public static object[] UnSupportedTableItemExpressionTestCases =
+ public static object[] UnsupportedTableItemExpressionTestCases =
{
new object[] { s_TEequalsUnsupported },
new object[] { s_TEequalsStaticUnsupported },
@@ -211,11 +212,38 @@ public void TestDictionaryTableEntityFilterExpressions(string expectedFilter, Ex
Assert.That(filter, Is.EqualTo(expectedFilter));
}
- [TestCaseSource(nameof(UnSupportedTableItemExpressionTestCases))]
+ [TestCaseSource(nameof(UnsupportedTableItemExpressionTestCases))]
[Test]
+ [NonParallelizable]
public void TestTableItemFilterExpressionsUnsupported(Expression> expression)
{
Assert.Throws(() => TableClient.CreateQueryFilter(expression));
}
+
+ [TestCaseSource(nameof(UnsupportedTableItemExpressionTestCases))]
+ [Test]
+ [NonParallelizable]
+ public void TestTableItemFilterExpressionsUnsupportedDoesNotThrowWithCompatSwitch(Expression> expression)
+ {
+ if (expression == s_TEequalsStaticUnsupported)
+ {
+ Assert.Ignore("Ignore this expression because it was never supported.");
+ }
+ using var ctx = new TestAppContextSwitch(TableConstants.CompatSwitches.DisableThrowOnStringComparisonFilterSwitchName, true.ToString());
+ TableClient.CreateQueryFilter(expression);
+ }
+
+ [TestCaseSource(nameof(UnsupportedTableItemExpressionTestCases))]
+ [Test]
+ [NonParallelizable]
+ public void TestTableItemFilterExpressionsUnsupportedDoesNotThrowWithCompatSwitchEnv(Expression> expression)
+ {
+ if (expression == s_TEequalsStaticUnsupported)
+ {
+ Assert.Ignore("Ignore this expression because it was never supported.");
+ }
+ using var env = new TestEnvVar(TableConstants.CompatSwitches.DisableThrowOnStringComparisonFilterEnvVar, true.ToString());
+ TableClient.CreateQueryFilter(expression);
+ }
}
}