Skip to content

Inline char constants as Unicode string literals in SQL Server IndexO… - #39104

Merged
AndriySvyryd merged 3 commits into
dotnet:mainfrom
ilkertskn:fix/sqlserver-char-constant-unicode-literal
Oct 3, 2026
Merged

AndriySvyryd merged 3 commits into
dotnet:mainfrom
ilkertskn:fix/sqlserver-char-constant-unicode-literal

Conversation

@ilkertskn

Copy link
Copy Markdown
Contributor

…f/Replace translations

SqlServerStringMethodTranslator applied CharTypeMapping to char arguments of string.IndexOf(char) and string.Replace(char, char). CharTypeMapping's literal has no N prefix, so a constant such as 'ş' or '中' was emitted as a non-Unicode literal and best-fit mapped to the database code page before the comparison: on the default collation CHARINDEX('ş', N'aşb') returns 0 while CHARINDEX('ş', N'asb') returns 2, and REPLACE(N'Şişlis', 'ş', 'x') replaces the trailing 's'. Passing the same char as a parameter (sent as nvarchar) gave the right answer, and an ExecuteUpdate with an inline char could silently corrupt data.

Emit char constants as string constants with the string argument's type mapping (N'ş' for nvarchar columns) and keep CharTypeMapping only for non-constant char expressions. Existing baselines change from 'e' to N'e' accordingly; a varchar column still gets a non-Unicode literal.

  • [x ] I've read the guidelines for contributing and seen the walkthrough
  • [x ] I've posted a comment on an issue with a detailed description of how I am planning to contribute and got approval from a member of the team
  • [x ] The code builds and tests pass locally (also verified by our automated build checks)
  • [ x] Commit messages follow this format:
        Summary of the changes
        - Detail 1
        - Detail 2

        Fixes #bugnumber
  • [x ] Tests for the changes have been added (for bug fixes / features)
  • [x ] Code follows the same patterns and style as existing code in this repo

…f/Replace translations

SqlServerStringMethodTranslator applied CharTypeMapping to char arguments of
string.IndexOf(char) and string.Replace(char, char). CharTypeMapping's literal has
no N prefix, so a constant such as 'ş' or '中' was emitted as a non-Unicode literal
and best-fit mapped to the database code page before the comparison: on the
default collation `CHARINDEX('ş', N'aşb')` returns 0 while `CHARINDEX('ş', N'asb')`
returns 2, and `REPLACE(N'Şişlis', 'ş', 'x')` replaces the trailing 's'. Passing the
same char as a parameter (sent as nvarchar) gave the right answer, and an
ExecuteUpdate with an inline char could silently corrupt data.

Emit char constants as string constants with the string argument's type mapping
(N'ş' for nvarchar columns) and keep CharTypeMapping only for non-constant char
expressions. Existing baselines change from 'e' to N'e' accordingly; a varchar
column still gets a non-Unicode literal.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

SQL Server bulk-update and non-Unicode column regression tests are still needed.

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

Fixes SQL Server IndexOf(char) and Replace(char, char) translations so constant characters use the string mapping and preserve Unicode behavior.

Changes:

  • Adds Unicode-safe constant character translation.
  • Adds non-ASCII regression coverage and updates provider baselines.
  • Preserves character mapping for non-constant expressions.
File Description
test/​EFCore.SqlServer.FunctionalTests/​Query/​Translations/​StringTranslationsSqlServerTest.cs Updates SQL Server translation baselines and tests.
test/​EFCore.Sqlite.FunctionalTests/​Query/​Translations/​StringTranslationsSqliteTest.cs Updates SQLite translation baselines.
test/​EFCore.Specification.Tests/​Query/​Translations/​StringTranslationsTestBase.cs Adds provider-independent regression tests.
test/​EFCore.Cosmos.FunctionalTests/​Query/​Translations/​StringTranslationsCosmosTest.cs Updates Cosmos translation baselines.
src/​EFCore.SqlServer/​Query/​Internal/​Translators/​SqlServerStringMethodTranslator.cs Applies string mappings to constant character arguments.

@ilkertskn ilkertskn left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i accept

…onstant

Covers the bulk-update path: without the fix the inline 'ş' was emitted as a
non-Unicode literal, so REPLACE never matched the appended 'ş' and the stored
value was left as "...ş" instead of "...x".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…erver

SQL Server has no char type, so a non-constant char (e.g. a parameter) is now sent
as a one-character string via a CharToStringConverter composed on the string type
mapping instead of using CharTypeMapping.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@AndriySvyryd AndriySvyryd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution!

@AndriySvyryd
AndriySvyryd merged commit 634135f into dotnet:main Oct 3, 2026
19 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants