If there is no data available for a field in a corrupted record, but the type is available, have the recovery extension substitute 0, 0.0, '' or X'' instead of a NULL value.

FossilOrigin-Name: 8eb326c24981647e2df90e4b9d75db52a552bd997bd821f5898c7ff3fb93a57d
This commit is contained in:
dan 2024-05-15 15:06:27 +00:00
parent f722d91fa8
commit 9a1a4822e8
5 changed files with 146 additions and 64 deletions

View File

@ -466,62 +466,74 @@ static void dbdataValue(
u8 *pData,
sqlite3_int64 nData
){
if( eType>=0 && dbdataValueBytes(eType)<=nData ){
switch( eType ){
case 0:
case 10:
case 11:
sqlite3_result_null(pCtx);
break;
case 8:
sqlite3_result_int(pCtx, 0);
break;
case 9:
sqlite3_result_int(pCtx, 1);
break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
sqlite3_uint64 v = (signed char)pData[0];
pData++;
switch( eType ){
case 7:
case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
case 4: v = (v<<8) + pData[0]; pData++;
case 3: v = (v<<8) + pData[0]; pData++;
case 2: v = (v<<8) + pData[0]; pData++;
}
if( eType==7 ){
double r;
memcpy(&r, &v, sizeof(r));
sqlite3_result_double(pCtx, r);
}else{
sqlite3_result_int64(pCtx, (sqlite3_int64)v);
}
break;
}
default: {
int n = ((eType-12) / 2);
if( eType % 2 ){
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);
break;
#endif
default:
sqlite3_result_text(pCtx, (char*)pData, n, SQLITE_TRANSIENT);
break;
if( eType>=0 ){
if( dbdataValueBytes(eType)<=nData ){
switch( eType ){
case 0:
case 10:
case 11:
sqlite3_result_null(pCtx);
break;
case 8:
sqlite3_result_int(pCtx, 0);
break;
case 9:
sqlite3_result_int(pCtx, 1);
break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
sqlite3_uint64 v = (signed char)pData[0];
pData++;
switch( eType ){
case 7:
case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
case 4: v = (v<<8) + pData[0]; pData++;
case 3: v = (v<<8) + pData[0]; pData++;
case 2: v = (v<<8) + pData[0]; pData++;
}
}else{
sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
if( eType==7 ){
double r;
memcpy(&r, &v, sizeof(r));
sqlite3_result_double(pCtx, r);
}else{
sqlite3_result_int64(pCtx, (sqlite3_int64)v);
}
break;
}
default: {
int n = ((eType-12) / 2);
if( eType % 2 ){
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);
break;
#endif
default:
sqlite3_result_text(pCtx, (char*)pData, n, SQLITE_TRANSIENT);
break;
}
}else{
sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
}
}
}
}else{
if( eType==7 ){
sqlite3_result_double(pCtx, 0.0);
}else if( eType<7 ){
sqlite3_result_int(pCtx, 0);
}else if( eType%2 ){
sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
}else{
sqlite3_result_blob(pCtx, "", 0, SQLITE_STATIC);
}
}
}

View File

@ -342,7 +342,7 @@ foreach enc {utf8 utf16 utf16le utf16be} {
DELETE FROM sqlite_schema WHERE name='t1';
}
proc my_sql_hook {sql} {
proc my_sql_hook2 {sql} {
if {[string match "INSERT INTO lostandfound*" $sql]} {
lappend ::script $sql
}
@ -350,7 +350,7 @@ foreach enc {utf8 utf16 utf16le utf16be} {
}
do_test 18.$enc.2 {
set ::script [list]
set R [sqlite3_recover_init_sql db main my_sql_hook]
set R [sqlite3_recover_init_sql db main my_sql_hook2]
$R config lostandfound lostandfound
$R run
$R finish
@ -358,7 +358,18 @@ foreach enc {utf8 utf16 utf16le utf16be} {
} {{INSERT INTO lostandfound VALUES(2, 2, 2, 1, 'abc', 'def')}}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 19.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
ALTER TABLE t1 ADD COLUMN c NOT NULL DEFAULT 13;
INSERT INTO t1 VALUES(3, 'three', 'hello world');
}
do_recover_test 19.1

View File

@ -0,0 +1,58 @@
# 2024 May 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
source [file join [file dirname [info script]] recover_common.tcl]
set testprefix recovercorrupt4
database_may_be_corrupt
do_execsql_test 1.0 {
CREATE TABLE rows(indexed INTEGER NOT NULL, unindexed INTEGER NOT NULL, filler BLOB NOT NULL DEFAULT 13);
-- CREATE UNIQUE INDEX rows_index ON rows(indexed);
INSERT INTO rows(indexed, unindexed, filler) VALUES(1, 1, x'31');
INSERT INTO rows(indexed, unindexed, filler) VALUES(2, 2, x'32');
INSERT INTO rows(indexed, unindexed, filler) VALUES(4, 4, x'34');
INSERT INTO rows(indexed, unindexed, filler) VALUES(8, 8, randomblob(2048));
}
db close
do_test 1.1 {
set sz [expr [file size test.db] - 1024]
set fd [open test.db]
fconfigure $fd -encoding binary -translation binary
set data [read $fd $sz]
set fd2 [open test.db2 w]
fconfigure $fd2 -encoding binary -translation binary
puts -nonewline $fd2 $data
close $fd2
set {} {}
} {}
do_test 1.2 {
forcedelete test.db3
sqlite3 db test.db2
set R [sqlite3_recover_init db main test.db3]
$R run
$R finish
} {}
do_test 1.3 {
sqlite3 db test.db3
execsql {
SELECT indexed, unindexed FROM rows
}
} {1 1 2 2 4 4 8 8}
finish_test

View File

@ -1,5 +1,5 @@
C Add\stests\sto\sbestindexC.test.\sNo\schanges\sto\scode.
D 2024-05-11T16:44:56.528
C If\sthere\sis\sno\sdata\savailable\sfor\sa\sfield\sin\sa\scorrupted\srecord,\sbut\sthe\stype\sis\savailable,\shave\sthe\srecovery\sextension\ssubstitute\s0,\s0.0,\s''\sor\sX''\sinstead\sof\sa\sNULL\svalue.
D 2024-05-15T15:06:27.777
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -478,14 +478,15 @@ F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69
F ext/rbu/sqlite3rbu.c 4a3376c0fb9a844a799ac529fb81260523f6b13c9f629bc270c632dbae5fc1f8
F ext/rbu/sqlite3rbu.h 9d923eb135c5d04aa6afd7c39ca47b0d1d0707c100e02f19fdde6a494e414304
F ext/rbu/test_rbu.c ee6ede75147bc081fe9bc3931e6b206277418d14d3fbceea6fdc6216d9b47055
F ext/recover/dbdata.c e518c1a221a259a1ea594d9db8fce356861bfa450e6f54eda999242b9bd5c50a
F ext/recover/recover1.test c484d01502239f11b61f23c1cee9f5dd19fa17617f8974e42e74d64639c524cf
F ext/recover/dbdata.c 0a943861ec096de375097e0aaff07b480a002eab9b01fecd3f9e828faf4ef624
F ext/recover/recover1.test e16d78e94183562abff569967b18b7c77451d7044365516cd0fe14713a284851
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
F ext/recover/recoverbuild.test c74170e0f7b02456af41838afeb5353fdb985a48cc2331d661bbabbca7c6b8e3
F ext/recover/recoverclobber.test 3ba6c0c373c5c63d17e82eced64c05c57ccaf26c1abe1ca7141334022a79f32e
F ext/recover/recovercorrupt.test 64c081ad1200ae77b447da99eb724785d6bf71715f394543dc7689642e92bf49
F ext/recover/recovercorrupt2.test 1418f1710debc24ff38276cedfcea234beb37a34205708e7e3e6d76cc4a979db
F ext/recover/recovercorrupt3.test 2e7b9a1b528ca23ed382cec6f64e3fcbbd0f8e852add7562397fd8df83f335d5
F ext/recover/recovercorrupt4.test 8990c3a76da616b938e800cd2b40eb1f7adf9352624966ba0af0303c7a015f00
F ext/recover/recoverfault.test 9d9f88eeb222615a25e7514f234c950d46bee20d24cd8db49d8fff8d650dcfe1
F ext/recover/recoverfault2.test 730e7371bcda769554d15460cb23126abba1be8eca9539ccabf63623e7bb7e09
F ext/recover/recoverold.test 68db3d6f85dd2b98e785b6c4da4f5eea4bbe52ccf6674d9a94c7506dc92596aa
@ -2190,8 +2191,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P c6fd70b3c23fa00eaac9286d4a67e5c8ac76f926c11c220250c34032647bedc1
R da518a0d510ea768080aa36a2357bedd
P 58d938c0e03c3c8d8796c537f89e69734ba6263d60ba37e345259cb6fdffbea5
R cd015e2f2734629b19947eb11f0220ff
U dan
Z 00211d5eb53202476ca10f2c5f60b56e
Z be5ac0bdafce0ff1c422be3037819109
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
58d938c0e03c3c8d8796c537f89e69734ba6263d60ba37e345259cb6fdffbea5
8eb326c24981647e2df90e4b9d75db52a552bd997bd821f5898c7ff3fb93a57d