mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-23 21:49:02 +03:00
The .recover command should not remove BOMs that are already inside the
database. [bugs:/info/2026-10-18T20:41:57Z|Bug 2026-10-18T20:41:57Z] FossilOrigin-Name: 69f4d423fa5538a555f862da3a1896e2fa3009dc650286042cb0beabe4dd2114
This commit is contained in:
@@ -511,11 +511,39 @@ static void dbdataValue(
|
||||
switch( enc ){
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
case SQLITE_UTF16BE:
|
||||
sqlite3_result_text16be(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
|
||||
break;
|
||||
case SQLITE_UTF16LE:
|
||||
sqlite3_result_text16le(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
|
||||
case SQLITE_UTF16LE: {
|
||||
/* sqlite3_result_text16be/le() remove a leading BOM. If
|
||||
** the stored text begins with U+FEFF or U+FFFE, prepend
|
||||
** a BOM in the database byte order, so that only the
|
||||
** added BOM is removed. */
|
||||
u8 *aBuf = 0;
|
||||
if( n>=2 && ((pData[0]==0xFE && pData[1]==0xFF)
|
||||
|| (pData[0]==0xFF && pData[1]==0xFE))
|
||||
){
|
||||
aBuf = (u8*)sqlite3_malloc64(n+2);
|
||||
if( aBuf==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
break;
|
||||
}
|
||||
aBuf[0] = (enc==SQLITE_UTF16BE) ? 0xFE : 0xFF;
|
||||
aBuf[1] = (enc==SQLITE_UTF16BE) ? 0xFF : 0xFE;
|
||||
memcpy(&aBuf[2], pData, n);
|
||||
}
|
||||
if( enc==SQLITE_UTF16BE ){
|
||||
if( aBuf ){
|
||||
sqlite3_result_text16be(pCtx, aBuf, n+2, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_result_text16be(pCtx, pData, n, SQLITE_TRANSIENT);
|
||||
}
|
||||
}else{
|
||||
if( aBuf ){
|
||||
sqlite3_result_text16le(pCtx, aBuf, n+2, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_result_text16le(pCtx, pData, n, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
sqlite3_result_text(pCtx, (char*)pData, n, SQLITE_TRANSIENT);
|
||||
|
||||
@@ -371,6 +371,60 @@ do_execsql_test 19.0 {
|
||||
|
||||
do_recover_test 19.1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Bug 2026-10-18T20:41:57Z
|
||||
#
|
||||
# In a UTF-16 database, TEXT values that begin with U+FEFF or U+FFFE
|
||||
# must be recovered unchanged. The leading character is part of the
|
||||
# value, not a byte-order mark. Values 4 and 5 are large enough to
|
||||
# spill onto overflow pages.
|
||||
#
|
||||
foreach enc {utf16le utf16be} {
|
||||
reset_db
|
||||
do_execsql_test 20.$enc.0 "
|
||||
PRAGMA encoding = '$enc';
|
||||
CREATE TABLE t1(id INTEGER PRIMARY KEY, a TEXT);
|
||||
INSERT INTO t1 VALUES
|
||||
(1, char(0xfeff)||'abc'),
|
||||
(2, char(0xfffe)||'xyz'),
|
||||
(3, 'plain'),
|
||||
(4, char(0xfeff)||printf('%.*c', 5000, 'a')),
|
||||
(5, char(0xfffe)||printf('%.*c', 5000, 'b'));
|
||||
"
|
||||
|
||||
set sql {
|
||||
SELECT id, length(a), unicode(a), hex(substr(a,1,3)), hex(substr(a,-2))
|
||||
FROM t1 ORDER BY id
|
||||
}
|
||||
set expect [db eval $sql]
|
||||
|
||||
# Recover directly into a new database.
|
||||
do_test 20.$enc.1 {
|
||||
forcedelete test.db2
|
||||
set R [sqlite3_recover_init db main test.db2]
|
||||
$R run
|
||||
$R finish
|
||||
sqlite3 db2 test.db2
|
||||
set res [db2 eval $sql]
|
||||
db2 close
|
||||
set res
|
||||
} $expect
|
||||
|
||||
# Recover as SQL text (the path used by the CLI ".recover" command).
|
||||
do_test 20.$enc.2 {
|
||||
forcedelete test.db2
|
||||
set ::sqlhook [list]
|
||||
set R [sqlite3_recover_init_sql db main my_sql_hook]
|
||||
$R run
|
||||
$R finish
|
||||
sqlite3 db2 test.db2
|
||||
db2 eval [join $::sqlhook ";"]
|
||||
set res [db2 eval $sql]
|
||||
db2 close
|
||||
set res
|
||||
} $expect
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
19
manifest
19
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\sthe\ssqlite3_bind_value()\sinterface\sso\sthat\sit\sdoes\snot\sremove\sa\nbyte-order\smark\son\sthe\svalue\sbeing\sbound.
|
||||
D 2026-10-23T15:30:27.214
|
||||
C The\s.recover\scommand\sshould\snot\sremove\sBOMs\sthat\sare\salready\sinside\sthe\ndatabase.\n[bugs:/info/2026-10-18T20:41:57Z|Bug\s2026-10-18T20:41:57Z]
|
||||
D 2026-10-23T15:52:17.165
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -478,8 +478,8 @@ F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69
|
||||
F ext/rbu/sqlite3rbu.c 29be4d2e7a7fbc8124545d2833570bdefef8724239c6cdd81a8d1e6dd07889f2
|
||||
F ext/rbu/sqlite3rbu.h e3a5bf21e09ca93ce4e8740e00d6a853e90a697968ec0ea98f40826938bdb68e
|
||||
F ext/rbu/test_rbu.c 8b6e64e486c28c41ef29f6f4ea6be7b3091958987812784904f5e903f6b56418
|
||||
F ext/recover/dbdata.c 10d3c56968a9af6853722a47280805ad1564714d79ea45ac6f7da14bb57fd137
|
||||
F ext/recover/recover1.test e16d78e94183562abff569967b18b7c77451d7044365516cd0fe14713a284851
|
||||
F ext/recover/dbdata.c d49c08a6aad98a0da9b31d80826878cd77350b7ef380755adf8b8565c67755f0
|
||||
F ext/recover/recover1.test 876a31d02568c62c27186d560f5ffb23beaf9c268455fbe035627e23892aee4f
|
||||
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
|
||||
F ext/recover/recoverbuild.test c74170e0f7b02456af41838afeb5353fdb985a48cc2331d661bbabbca7c6b8e3
|
||||
F ext/recover/recoverclobber.test 3ba6c0c373c5c63d17e82eced64c05c57ccaf26c1abe1ca7141334022a79f32e
|
||||
@@ -999,7 +999,7 @@ F test/bigmmap.test 6021e205487347c6d7e5a541aa472a4b8efc4e9f4a3799a823b61a8e6616
|
||||
F test/bigrow.test 3e6b189dea465a78306eac67fc6754c1cf90eb1694a25c88c338900c216c1e6b
|
||||
F test/bigsort.test 997e172009905873c06426145e4b3794c7dfe2d563724cb2fd39d45f319cf3d2
|
||||
F test/bind.test 1e136709b306f7ed3192d349c2930d89df6ab621654ad6f1a72381d3fe76f483
|
||||
F test/bind2.test 918bc35135f4141809ead7585909cde57d44db90a7a62aef540127148f91aab7
|
||||
F test/bind2.test e7914a9c670ff230d4fe6700d08becf4aff203ab2a3b48e4df6481e6c3526b77
|
||||
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
|
||||
F test/bitvec.test 75894a880520164d73b1305c1c3f96882615e142
|
||||
F test/blob.test e7ac6c7d3a985cc4678c64f325292529a69ae252
|
||||
@@ -2297,11 +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 8a0296aa4db20cdcbbfaa0e4c61b5fe339b0514cf73832253ff0abd1ce59d31c
|
||||
R 1dd3a5c88fdf1dc284f23dd932cd9767
|
||||
T *branch * bom-handling
|
||||
T *sym-bom-handling *
|
||||
T -sym-trunk *
|
||||
P 56e268312d038608b5fb2a8ed24002f478ad5a22eb0214b1a064f2926aada66c
|
||||
R 2e2481a1862ff08eb99bf69c8be110d9
|
||||
U drh
|
||||
Z e0a3b639a8ffa1ff10e4b189ad45981e
|
||||
Z cc48029ffcfda22369666c438d0c5d3d
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
56e268312d038608b5fb2a8ed24002f478ad5a22eb0214b1a064f2926aada66c
|
||||
69f4d423fa5538a555f862da3a1896e2fa3009dc650286042cb0beabe4dd2114
|
||||
|
||||
@@ -36,6 +36,50 @@ do_test 1.1 {
|
||||
} {42.0}
|
||||
sqlite3_finalize $stmt
|
||||
|
||||
|
||||
# Bug 2026-10-18T20:41:57Z
|
||||
#
|
||||
# In a UTF-16 database, using sqlite3_bind_value() to copy a TEXT value
|
||||
# that begins with U+FEFF or U+FFFE should copy the value exactly. The
|
||||
# leading character is not a byte-order mark.
|
||||
#
|
||||
foreach enc {utf16le utf16be} {
|
||||
forcedelete test.db3
|
||||
sqlite3 db3 test.db3
|
||||
do_execsql_test -db db3 2.$enc.0 "
|
||||
PRAGMA encoding = '$enc';
|
||||
CREATE TABLE t2(id INTEGER PRIMARY KEY, a TEXT);
|
||||
INSERT INTO t2 VALUES
|
||||
(1, char(0xfeff)||'abc'),
|
||||
(2, char(0xfffe)||'xyz'),
|
||||
(3, 'plain'),
|
||||
(4, char(0xfeff)||printf('%.*c', 5000, 'a')),
|
||||
(5, char(0xfffe)||printf('%.*c', 5000, 'b'));
|
||||
"
|
||||
foreach {id res} {
|
||||
1 {4 65279 1}
|
||||
2 {4 65534 1}
|
||||
3 {5 112 1}
|
||||
4 {5001 65279 1}
|
||||
5 {5001 65534 1}
|
||||
} {
|
||||
do_test 2.$enc.$id {
|
||||
set stmt [sqlite3_prepare db3 {
|
||||
SELECT length(?1), unicode(?1), ?1=(SELECT a FROM t2 WHERE id=?2)
|
||||
} -1 tail]
|
||||
sqlite3_bind_int $stmt 2 $id
|
||||
sqlite3_bind_value_from_select $stmt 1 "SELECT a FROM t2 WHERE id=$id"
|
||||
sqlite3_step $stmt
|
||||
set r [list [sqlite3_column_int $stmt 0] \
|
||||
[sqlite3_column_int $stmt 1] \
|
||||
[sqlite3_column_int $stmt 2]]
|
||||
sqlite3_finalize $stmt
|
||||
set r
|
||||
} $res
|
||||
}
|
||||
db3 close
|
||||
}
|
||||
|
||||
ifcapable !preupdate {
|
||||
finish_test
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user