diff --git a/manifest b/manifest index b0057712c8..1b51aba0e4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\sFTS5\sfix\sfrom\sbranch-3.54 -D 2026-10-23T12:51:22.852 +C Follow\sdocumented\sbehavior\swhen\scasting\sa\szeroblob()\sto\stext\son\sa\sUTF-16\ndatabase.\s[bugs:/info/2026-10-23T12:45:59Z|bug\s2026-10-23T12:45:59Z] +D 2026-10-23T13:06:30.822 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -877,7 +877,7 @@ F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 7bb9e161f05986446186513a5c9498455930069c2177b12e074a46fa006890c5 F src/vdbe.h b6ffb28da04363fd5d439b8204118fd3f2e751abe4f8e3edb089155fb90d4607 F src/vdbeInt.h 581b112c6a763a5871ae1d2b948c5288e749d03c7e3829ebce2738402fe21074 -F src/vdbeapi.c ebaf26be7511d002a573312ddd1976199b5aa24e8be6446aa32438c99f8f17c4 +F src/vdbeapi.c 4b38eb061fe6a8e96055e74d9301f0f36e453855e650a3e5fdd25ad45c7d0d7e F src/vdbeaux.c 7e3975222531284ff14cb1be93b5751f6a3392a56d86d6329fcaa120471f56f3 F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 F src/vdbemem.c cf4000a8b355be2028b290516898ff99d611c0d33397ac6c4f6d77f84dcd39fb @@ -2196,7 +2196,7 @@ F test/without_rowid6.test efbd7add62c59bf5ca97bf8da674e734e6a70ef979234e8161668 F test/without_rowid7.test 747d3fbef7108d416d6416694b03d8ff046dc9cc82b3d911715feb472444b95a F test/wordcount.c d721a4b6fae93e6e33449700bce1686bc23257c27425bc3ef1599dc912adec66 F test/writecrash.test 13520af28f376bfc8c0bcd130efc1fff20bb165198e8b94cf153f1f754154bb9 -F test/zeroblob.test 7b74cefc7b281dfa2b07cd237987fbe94b4a2037a7771e9e83f2d5f608b1d99e +F test/zeroblob.test ad710990fa13fe969101b5c2a52e95f62f4c16f75ad306eb78a6c05dc9a12e97 F test/zeroblobfault.test 861d8191a0d944dfebb3cb4d2c5b4e46a5a119eaec5a63dd996c2389f8063441 F test/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc F test/zipfile.test 88b8b8babbe24dd3c1e58e8f96685429029c283fbf54b6df07b145b66032de9a @@ -2297,8 +2297,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b33ff35e6246a9dc62205db244511eead28fae90cea686e205effae5e6cc5b49 599f3345b99b79e11a71bd0087555d0980f2af5cffb6b78683a5027e78f67831 -R dba6315bf647db8443d61e41b60ad9e9 +P 320cb1f51382868ed576d8fa52c75672a2c3e4cee99f868385645bd9a370457a +R 0517e9b64f9f1be95cb3761b01d34e64 U drh -Z 6bee0e48227c051076b2df8029557200 +Z fe678a626872621c9456ec3e5b057ad7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d520928048..85784636a8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -320cb1f51382868ed576d8fa52c75672a2c3e4cee99f868385645bd9a370457a +8a0296aa4db20cdcbbfaa0e4c61b5fe339b0514cf73832253ff0abd1ce59d31c diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 8ae5f50790..abdbb342f4 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -691,6 +691,7 @@ int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ } #ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); + pOut->enc = pCtx->enc; return SQLITE_OK; #else return sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); @@ -2017,6 +2018,7 @@ int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ #else rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); #endif + p->aVar[i-1].enc = ENC(p->db); sqlite3_mutex_leave(p->db->mutex); } return rc; diff --git a/test/zeroblob.test b/test/zeroblob.test index df234eea44..93f229ffdd 100644 --- a/test/zeroblob.test +++ b/test/zeroblob.test @@ -339,5 +339,86 @@ do_execsql_test 13.100 { SELECT a, quote(b), length(b), c FROM t1; } {1 X'0000000000000000' 8 3} +# 2026-10-23 https://sqlite.org/bugs/info/420911fdac2d68af +# +# In a non-UTF-8 database, a zeroblob() used as text was formerly +# converted from UTF-8, so each zero byte became one character of the +# database encoding. A zeroblob value must read back as text identically +# to the same bytes supplied as a BLOB literal or stored in a table. +# +foreach {tn enc} {14 UTF-16le 15 UTF-16be} { + reset_db + db eval "PRAGMA encoding='$enc'" + do_execsql_test $tn.1 { + CREATE TABLE t1(b); + INSERT INTO t1 VALUES(zeroblob(4)); + CREATE TABLE t2(c); + INSERT INTO t2 VALUES('ab'),('abc'); + } + + # zeroblob(4) cast to text is the same 4 bytes as the literal, the + # stored value, and the value from a materialized CTE. + do_execsql_test $tn.2 { + SELECT hex(CAST(zeroblob(4) AS TEXT)); + } {00000000} + do_execsql_test $tn.3 { + SELECT hex(CAST(x'00000000' AS TEXT)); + } {00000000} + do_execsql_test $tn.4 { + SELECT hex(CAST(b AS TEXT)) FROM t1; + } {00000000} + do_execsql_test $tn.5 { + WITH x AS MATERIALIZED (SELECT zeroblob(4) AS b FROM t1) + SELECT hex(CAST(b AS TEXT)) FROM x; + } {00000000} + + # The value compares equal, and has the same length, either way. + do_execsql_test $tn.6 { + SELECT CAST(zeroblob(4) AS TEXT)=CAST(x'00000000' AS TEXT); + } {1} + do_execsql_test $tn.7 { + SELECT octet_length(CAST(zeroblob(4) AS TEXT)), + octet_length(CAST(x'00000000' AS TEXT)); + } {4 4} + + # upper()/lower() see the value as the database encoding, not UTF-8. + do_execsql_test $tn.8 { + SELECT hex(upper(zeroblob(4))), hex(upper(x'00000000')); + } {00000000 00000000} + do_execsql_test $tn.9 { + SELECT hex(lower(zeroblob(4))), hex(lower(x'00000000')); + } {00000000 00000000} + + # The plan no longer changes the result: inlined and materialized agree. + do_execsql_test $tn.10 { + WITH x AS (SELECT zeroblob(length(c)) AS z FROM t2) + SELECT count(*) FROM (SELECT 1 FROM x GROUP BY upper(z)); + } {1} + do_execsql_test $tn.11 { + WITH x AS MATERIALIZED (SELECT zeroblob(length(c)) AS z FROM t2) + SELECT count(*) FROM (SELECT 1 FROM x GROUP BY upper(z)); + } {1} + + # sqlite3_bind_zeroblob() and sqlite3_bind_zeroblob64() behave like a + # bound BLOB of the same zero bytes. + set stmt [sqlite3_prepare db {SELECT hex(CAST(?1 AS TEXT))} -1 dummy] + do_test $tn.12 { + sqlite3_bind_zeroblob $stmt 1 4 + sqlite3_step $stmt + set ret [sqlite3_column_text $stmt 0] + sqlite3_reset $stmt + set ret + } {00000000} + do_test $tn.13 { + sqlite3_bind_zeroblob64 $stmt 1 4 + sqlite3_step $stmt + set ret [sqlite3_column_text $stmt 0] + sqlite3_reset $stmt + set ret + } {00000000} + sqlite3_finalize $stmt +} +reset_db + test_restore_config_pagecache finish_test