fix(sql-dialect): enforce Postgres/Oracle identifier ceilings in UTF-8 bytes (Driver.Sql.Dialect-001)

NAMEDATALEN-1 (63) and Oracle 12.2's 128 are byte limits in the database
encoding, not character counts, so a 32-character Cyrillic name passed
ident.Length and was then silently truncated (Postgres) or rejected by the
server (Oracle). Both dialects now measure Encoding.UTF8.GetByteCount and say
'bytes' in the rejection. SqlServerDialect deliberately keeps ident.Length —
sysname is nvarchar(128), a real character limit — pinned by a control test.
This commit is contained in:
Joseph Doherty
2026-08-10 07:58:04 -04:00
parent 94b8633e68
commit 74594e6083
6 changed files with 102 additions and 8 deletions
@@ -117,6 +117,19 @@ public class SqlServerDialectTests
Should.Throw<ArgumentException>(() => d.QuoteIdentifier(new string('a', 129)));
}
/// <summary>
/// The falsifiability control for the Postgres/Oracle byte ceilings: T-SQL's <c>sysname</c> is
/// <c>nvarchar(128)</c>, a genuine <b>128-character</b> (UTF-16 code unit) limit, so a 128-character
/// Cyrillic name — 256 UTF-8 bytes — is legal here and must still be accepted. A byte rule applied
/// uniformly across the three dialects would reject it, and only this test would say so.
/// </summary>
[Fact]
public void QuoteIdentifier_countsCharacters_notBytes_becauseSysnameIsNvarchar128()
{
var ident = new string('б', 128); // 128 chars, 256 UTF-8 bytes
new SqlServerDialect().QuoteIdentifier(ident).ShouldBe("[" + ident + "]");
}
[Fact]
public void QuoteIdentifier_neutralisesAClassicInjectionPayload()
{