1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Fix recovery of utf-16 databases.

FossilOrigin-Name: 5b05be0861f35804270fbd184ad4b89c23e98cc2fbd56b9e4fe6197daef5fe49
This commit is contained in:
dan
2022-09-14 16:37:59 +00:00
parent 322967df59
commit b8eaf9a10d
7 changed files with 138 additions and 23 deletions

View File

@ -75,6 +75,7 @@
#include "sqlite3ext.h" #include "sqlite3ext.h"
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned int u32;
#endif #endif
SQLITE_EXTENSION_INIT1 SQLITE_EXTENSION_INIT1
@ -107,6 +108,7 @@ struct DbdataCursor {
int iField; /* Current field number */ int iField; /* Current field number */
u8 *pHdrPtr; u8 *pHdrPtr;
u8 *pPtr; u8 *pPtr;
u32 enc; /* Text encoding */
sqlite3_int64 iIntkey; /* Integer key value */ sqlite3_int64 iIntkey; /* Integer key value */
}; };
@ -299,14 +301,14 @@ static int dbdataClose(sqlite3_vtab_cursor *pCursor){
/* /*
** Utility methods to decode 16 and 32-bit big-endian unsigned integers. ** Utility methods to decode 16 and 32-bit big-endian unsigned integers.
*/ */
static unsigned int get_uint16(unsigned char *a){ static u32 get_uint16(unsigned char *a){
return (a[0]<<8)|a[1]; return (a[0]<<8)|a[1];
} }
static unsigned int get_uint32(unsigned char *a){ static u32 get_uint32(unsigned char *a){
return ((unsigned int)a[0]<<24) return ((u32)a[0]<<24)
| ((unsigned int)a[1]<<16) | ((u32)a[1]<<16)
| ((unsigned int)a[2]<<8) | ((u32)a[2]<<8)
| ((unsigned int)a[3]); | ((u32)a[3]);
} }
/* /*
@ -321,7 +323,7 @@ static unsigned int get_uint32(unsigned char *a){
*/ */
static int dbdataLoadPage( static int dbdataLoadPage(
DbdataCursor *pCsr, /* Cursor object */ DbdataCursor *pCsr, /* Cursor object */
unsigned int pgno, /* Page number of page to load */ u32 pgno, /* Page number of page to load */
u8 **ppPage, /* OUT: pointer to page buffer */ u8 **ppPage, /* OUT: pointer to page buffer */
int *pnPage /* OUT: Size of (*ppPage) in bytes */ int *pnPage /* OUT: Size of (*ppPage) in bytes */
){ ){
@ -405,6 +407,7 @@ static int dbdataValueBytes(int eType){
*/ */
static void dbdataValue( static void dbdataValue(
sqlite3_context *pCtx, sqlite3_context *pCtx,
u32 enc,
int eType, int eType,
u8 *pData, u8 *pData,
int nData int nData
@ -449,7 +452,17 @@ static void dbdataValue(
default: { default: {
int n = ((eType-12) / 2); int n = ((eType-12) / 2);
if( eType % 2 ){ if( eType % 2 ){
sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT); switch( enc ){
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);
break;
default:
sqlite3_result_text(pCtx, (char*)pData, n, SQLITE_TRANSIENT);
break;
}
}else{ }else{
sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT); sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
} }
@ -588,7 +601,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
/* Load content from overflow pages */ /* Load content from overflow pages */
if( nPayload>nLocal ){ if( nPayload>nLocal ){
sqlite3_int64 nRem = nPayload - nLocal; sqlite3_int64 nRem = nPayload - nLocal;
unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]); u32 pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
while( nRem>0 ){ while( nRem>0 ){
u8 *aOvfl = 0; u8 *aOvfl = 0;
int nOvfl = 0; int nOvfl = 0;
@ -703,6 +716,25 @@ static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){
return rc; return rc;
} }
/*
** Attempt to figure out the encoding of the database by retrieving page 1
** and inspecting the header field. If successful, set the pCsr->enc variable
** and return SQLITE_OK. Otherwise, return an SQLite error code.
*/
static int dbdataGetEncoding(DbdataCursor *pCsr){
int rc = SQLITE_OK;
int nPg1 = 0;
u8 *aPg1 = 0;
rc = dbdataLoadPage(pCsr, 1, &aPg1, &nPg1);
assert( rc!=SQLITE_OK || nPg1==0 || nPg1>=512 );
if( rc==SQLITE_OK && nPg1>0 ){
pCsr->enc = get_uint32(&aPg1[56]);
}
sqlite3_free(aPg1);
return rc;
}
/* /*
** xFilter method for sqlite_dbdata and sqlite_dbptr. ** xFilter method for sqlite_dbdata and sqlite_dbptr.
*/ */
@ -725,7 +757,6 @@ static int dbdataFilter(
pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]);
pCsr->bOnePage = 1; pCsr->bOnePage = 1;
}else{ }else{
pCsr->nPage = dbdataDbsize(pCsr, zSchema);
rc = dbdataDbsize(pCsr, zSchema); rc = dbdataDbsize(pCsr, zSchema);
} }
@ -754,6 +785,13 @@ static int dbdataFilter(
}else{ }else{
pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
} }
/* Try to determine the encoding of the db by inspecting the header
** field on page 1. */
if( rc==SQLITE_OK ){
rc = dbdataGetEncoding(pCsr);
}
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = dbdataNext(pCursor); rc = dbdataNext(pCursor);
} }
@ -808,7 +846,8 @@ static int dbdataColumn(
sqlite3_int64 iType; sqlite3_int64 iType;
dbdataGetVarint(pCsr->pHdrPtr, &iType); dbdataGetVarint(pCsr->pHdrPtr, &iType);
dbdataValue( dbdataValue(
ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr ctx, pCsr->enc, iType, pCsr->pPtr,
&pCsr->pRec[pCsr->nRec] - pCsr->pPtr
); );
} }
break; break;

View File

@ -192,6 +192,7 @@ do_execsql_test 11.1 {
INSERT INTO u1 VALUES('edvin marton', 'bond'); INSERT INTO u1 VALUES('edvin marton', 'bond');
INSERT INTO u1 VALUES(1, 4.0); INSERT INTO u1 VALUES(1, 4.0);
} }
do_recover_test 11 do_recover_test 11

View File

@ -78,7 +78,6 @@ ifcapable utf16 {
faultsim_save_and_close faultsim_save_and_close
proc my_sql_hook {sql} { proc my_sql_hook {sql} {
puts "HOOK $sql"
lappend ::lSql $sql lappend ::lSql $sql
return 0 return 0
} }

View File

@ -229,6 +229,40 @@ static int test_sqlite3_recover_init(
return TCL_OK; return TCL_OK;
} }
/*
** Declaration for public API function in file dbdata.c. This may be called
** with NULL as the final two arguments to register the sqlite_dbptr and
** sqlite_dbdata virtual tables with a database handle.
*/
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_dbdata_init(sqlite3*, char**, const sqlite3_api_routines*);
/*
** sqlite3_recover_init DB DBNAME URI
*/
static int test_sqlite3_dbdata_init(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db = 0;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, objv[1], &db) ) return TCL_ERROR;
sqlite3_dbdata_init(db, 0, 0);
Tcl_ResetResult(interp);
return TCL_OK;
}
int TestRecover_Init(Tcl_Interp *interp){ int TestRecover_Init(Tcl_Interp *interp){
struct Cmd { struct Cmd {
const char *zCmd; const char *zCmd;
@ -237,6 +271,7 @@ int TestRecover_Init(Tcl_Interp *interp){
} aCmd[] = { } aCmd[] = {
{ "sqlite3_recover_init", test_sqlite3_recover_init, 0 }, { "sqlite3_recover_init", test_sqlite3_recover_init, 0 },
{ "sqlite3_recover_init_sql", test_sqlite3_recover_init, (void*)1 }, { "sqlite3_recover_init_sql", test_sqlite3_recover_init, (void*)1 },
{ "sqlite3_dbdata_init", test_sqlite3_dbdata_init, (void*)1 },
}; };
int i; int i;

View File

@ -1,5 +1,5 @@
C Add\sOOM\stests\sfor\sthe\srecovery\sextension. C Fix\srecovery\sof\sutf-16\sdatabases.
D 2022-09-13T20:40:57.096 D 2022-09-14T16:37:59.285
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -299,7 +299,7 @@ F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c8
F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9 F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9 F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
F ext/misc/csv.c ca8d6dafc5469639de81937cb66ae2e6b358542aba94c4f791910d355a8e7f73 F ext/misc/csv.c ca8d6dafc5469639de81937cb66ae2e6b358542aba94c4f791910d355a8e7f73
F ext/misc/dbdata.c 9bb3666519bd8a54cce4934076a557fe6441c5bafce7e9c24d8b5ced148e8154 F ext/misc/dbdata.c ca7b235fa2396e8fc2e950826872f820f31268ac2cb51368b0d655bb71568f07
F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01 F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01
F ext/misc/decimal.c 09f967dcf4a1ee35a76309829308ec278d3648168733f4a1147820e11ebefd12 F ext/misc/decimal.c 09f967dcf4a1ee35a76309829308ec278d3648168733f4a1147820e11ebefd12
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
@ -387,18 +387,18 @@ F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2
F ext/rbu/sqlite3rbu.c 8737cabdfbee84bb25a7851ecef8b1312be332761238da9be6ddb10c62ad4291 F ext/rbu/sqlite3rbu.c 8737cabdfbee84bb25a7851ecef8b1312be332761238da9be6ddb10c62ad4291
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812 F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/recover/recover1.test 623afa77b91996bb1319b069ced5245c243caa995f66793d6879fbc2c190f0be F ext/recover/recover1.test 167ad4b267f6db5c06963a72196527cb42369c7cd77de2b4273d9fdc8bd7a254
F ext/recover/recover_common.tcl 6679af7dffc858e345053a91c9b0a897595b4a13007aceffafca75304ccb137c F ext/recover/recover_common.tcl 6679af7dffc858e345053a91c9b0a897595b4a13007aceffafca75304ccb137c
F ext/recover/recoverclobber.test 294dcc894124ab4ca3a7b35766630742a3d25810fceac22220beb64f70a33a60 F ext/recover/recoverclobber.test 294dcc894124ab4ca3a7b35766630742a3d25810fceac22220beb64f70a33a60
F ext/recover/recovercorrupt.test e3f3cbe0162ba681518aac9ea0ae8119f32ac93fb0900b5f09b6318966108e54 F ext/recover/recovercorrupt.test e3f3cbe0162ba681518aac9ea0ae8119f32ac93fb0900b5f09b6318966108e54
F ext/recover/recoverfault.test f3587c218c448545a082b99d59294dff5ec0b7daa15b0556cf926f6c350f221e F ext/recover/recoverfault.test f3587c218c448545a082b99d59294dff5ec0b7daa15b0556cf926f6c350f221e
F ext/recover/recoverfault2.test 699b3ec07ba6982291e65e1811807f18d7f115234b407c819eaf3529878867f5 F ext/recover/recoverfault2.test 321036336af23e778a87f148c4cc4407f88fbdab1fd72ddb661669be9020d36b
F ext/recover/recoverold.test 46e9d99b595fac583d4c67f74d7d89c20a435c752ef6eeb3e918b599940c88e0 F ext/recover/recoverold.test 46e9d99b595fac583d4c67f74d7d89c20a435c752ef6eeb3e918b599940c88e0
F ext/recover/recoverrowid.test 1694a1a5526d825f71279f3d02ab02a1ee4c5265de18858bf54cb8ec54487ac8 F ext/recover/recoverrowid.test 1694a1a5526d825f71279f3d02ab02a1ee4c5265de18858bf54cb8ec54487ac8
F ext/recover/recoversql.test f9872ff2114e13ffd8ee31e1de06919f62b9b48bc080191b5bd076d10becb60f F ext/recover/recoversql.test f9872ff2114e13ffd8ee31e1de06919f62b9b48bc080191b5bd076d10becb60f
F ext/recover/sqlite3recover.c 1afcac2bbfcf5ef67a3391f59678dc866348ac88745067e683052ede02c425fb F ext/recover/sqlite3recover.c 1afcac2bbfcf5ef67a3391f59678dc866348ac88745067e683052ede02c425fb
F ext/recover/sqlite3recover.h 81108efb8c4618d3d9c6da4df785212b0e4501aa0d25edfc463405fe839a6640 F ext/recover/sqlite3recover.h 81108efb8c4618d3d9c6da4df785212b0e4501aa0d25edfc463405fe839a6640
F ext/recover/test_recover.c 5941ecf484b6158be26e34c6f7b6c7f03967c72a63db0c08e7fd0fa43023eafa F ext/recover/test_recover.c 6a6f86ea61d728c67382047d574c62df83e6a28db23c329e93a177093689cd20
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15 F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
F ext/repair/checkfreelist.c e21f06995ff4efdc1622dcceaea4dcba2caa83ca2f31a1607b98a8509168a996 F ext/repair/checkfreelist.c e21f06995ff4efdc1622dcceaea4dcba2caa83ca2f31a1607b98a8509168a996
F ext/repair/checkindex.c 4383e4469c21e5b9ae321d0d63cec53e981af9d7a6564be6374f0eeb93dfc890 F ext/repair/checkindex.c 4383e4469c21e5b9ae321d0d63cec53e981af9d7a6564be6374f0eeb93dfc890
@ -1536,7 +1536,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d1631311a16 F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d1631311a16
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl d759ac44a501fb832f2ea966429ca18acfba0f9a8d34ad5c499332b079b37023 F test/tester.tcl 65c29b6f1dbf71b0e59a7b221d7e849dfa5a55fa7d0a2902811e8abdecdb1d44
F test/testrunner.tcl 86b57135754ab2160aeb04b4829d321fb285a5cfa7a505fe61d69aed605854cc F test/testrunner.tcl 86b57135754ab2160aeb04b4829d321fb285a5cfa7a505fe61d69aed605854cc
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899 F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502 F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
@ -2011,8 +2011,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 60089547e1fc77ecc02f207ebf75ee3160e5ff25f41d12e02e170fd7fde66602 P 9b6b4c7162439a889144edb561356afc66436db921a867c20871f0c556716502
R 4e62121f5a47cd1728b6e036c3f3c8c0 R 7d7577824671621531c65dae0de3846f
U dan U dan
Z 5fc633ab904798afb52a452a7e949f53 Z b3ef1682460d7df284b8cd64863e6715
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
9b6b4c7162439a889144edb561356afc66436db921a867c20871f0c556716502 5b05be0861f35804270fbd184ad4b89c23e98cc2fbd56b9e4fe6197daef5fe49

View File

@ -1548,6 +1548,47 @@ proc explain_i {sql {db db}} {
output2 "---- ------------ ------ ------ ------ ---------------- -- -" output2 "---- ------------ ------ ------ ------ ---------------- -- -"
} }
proc execsql_pp {sql {db db}} {
set nCol 0
$db eval $sql A {
if {$nCol==0} {
set nCol [llength $A(*)]
foreach c $A(*) {
set aWidth($c) [string length $c]
lappend data $c
}
}
foreach c $A(*) {
set n [string length $A($c)]
if {$n > $aWidth($c)} {
set aWidth($c) $n
}
lappend data $A($c)
}
}
if {$nCol>0} {
set nTotal 0
foreach e [array names aWidth] { incr nTotal $aWidth($e) }
incr nTotal [expr ($nCol-1) * 3]
incr nTotal 4
set fmt ""
foreach c $A(*) {
lappend fmt "% -$aWidth($c)s"
}
set fmt "| [join $fmt { | }] |"
puts [string repeat - $nTotal]
for {set i 0} {$i < [llength $data]} {incr i $nCol} {
set vals [lrange $data $i [expr $i+$nCol-1]]
puts [format $fmt {*}$vals]
if {$i==0} { puts [string repeat - $nTotal] }
}
puts [string repeat - $nTotal]
}
}
# Show the VDBE program for an SQL statement but omit the Trace # Show the VDBE program for an SQL statement but omit the Trace
# opcode at the beginning. This procedure can be used to prove # opcode at the beginning. This procedure can be used to prove
# that different SQL statements generate exactly the same VDBE code. # that different SQL statements generate exactly the same VDBE code.