From 655a1b7b58e614f67108f8f9a6e0995dc87169a2 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 24 Apr 2023 19:22:21 +0000 Subject: [PATCH 01/16] Allow the sessions module to be configured to capture changes from tables with no explicit PRIMARY KEY. FossilOrigin-Name: 8a612f0860126c0c8473b1e65fcabb9a8821d8bf09fdf3f6018acfc99df9af71 --- ext/session/sessionD.test | 24 --- ext/session/session_common.tcl | 52 ++++++ ext/session/sessionrebase.test | 76 +++++++++ ext/session/sessionrowid.test | 281 +++++++++++++++++++++++++++++++++ ext/session/sessionsize.test | 14 +- ext/session/sqlite3session.c | 253 ++++++++++++++++++++--------- ext/session/sqlite3session.h | 15 +- ext/session/test_session.c | 26 ++- manifest | 30 ++-- manifest.uuid | 2 +- 10 files changed, 649 insertions(+), 124 deletions(-) create mode 100644 ext/session/sessionrowid.test diff --git a/ext/session/sessionD.test b/ext/session/sessionD.test index ec652e2d6b..9fccbfa96f 100644 --- a/ext/session/sessionD.test +++ b/ext/session/sessionD.test @@ -41,30 +41,6 @@ proc scksum {db dbname} { return [md5 $txt] } -proc do_diff_test {tn setup} { - reset_db - forcedelete test.db2 - execsql { ATTACH 'test.db2' AS aux } - execsql $setup - - sqlite3session S db main - foreach tbl [db eval {SELECT name FROM sqlite_master WHERE type='table'}] { - S attach $tbl - S diff aux $tbl - } - - set C [S changeset] - S delete - - sqlite3 db2 test.db2 - sqlite3changeset_apply db2 $C "" - uplevel do_test $tn.1 [list {execsql { PRAGMA integrity_check } db2}] ok - db2 close - - set cksum [scksum db main] - uplevel do_test $tn.2 [list {scksum db aux}] [list $cksum] -} - # Ensure that the diff produced by comparing the current contents of [db] # with itself is empty. proc do_empty_diff_test {tn} { diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl index 22e427f2be..3ff84f1c5e 100644 --- a/ext/session/session_common.tcl +++ b/ext/session/session_common.tcl @@ -52,6 +52,7 @@ proc do_conflict_test {tn args} { proc bgerror {args} { set ::background_error $args } sqlite3session S db main + S object_config rowid 1 foreach t $O(-tables) { S attach $t } execsql $O(-sql) @@ -81,6 +82,7 @@ proc changeset_from_sql {sql {dbname main}} { } set rc [catch { sqlite3session S db $dbname + S object_config rowid 1 db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { S attach $name } @@ -138,6 +140,7 @@ proc do_then_apply_sql {args} { proc xConflict args { incr ::n_conflict ; return "OMIT" } set rc [catch { sqlite3session S db $dbname + S object_config rowid 1 db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { S attach $name } @@ -162,6 +165,8 @@ proc do_then_apply_sql {args} { proc do_iterator_test {tn tbl_list sql res} { sqlite3session S db main + S object_config rowid 1 + if {[llength $tbl_list]==0} { S attach * } foreach t $tbl_list {S attach $t} @@ -171,6 +176,7 @@ proc do_iterator_test {tn tbl_list sql res} { foreach v $res { lappend r $v } set x [list] +# set ::c [S changeset] ; execsql_pp { SELECT quote($::c) } sqlite3session_foreach c [S changeset] { lappend x $c } uplevel do_test $tn [list [list set {} $x]] [list $r] @@ -245,3 +251,49 @@ proc number_name {n} { if {$txt==""} {set txt zero} return $txt } + +proc scksum {db dbname} { + + if {$dbname=="temp"} { + set master sqlite_temp_master + } else { + set master $dbname.sqlite_master + } + + set alltab [$db eval "SELECT name FROM $master WHERE type='table'"] + set txt [$db eval "SELECT * FROM $master ORDER BY type,name,sql"] + foreach tab $alltab { + set cols [list] + db eval "PRAGMA $dbname.table_info = $tab" x { + lappend cols "quote($x(name))" + } + set cols [join $cols ,] + append txt [db eval "SELECT $cols FROM $dbname.$tab ORDER BY $cols"] + } + return [md5 $txt] +} + +proc do_diff_test {tn setup} { + reset_db + forcedelete test.db2 + execsql { ATTACH 'test.db2' AS aux } + execsql $setup + + sqlite3session S db main + S object_config rowid 1 + foreach tbl [db eval {SELECT name FROM sqlite_master WHERE type='table'}] { + S attach $tbl + S diff aux $tbl + } + + set C [S changeset] + S delete + + sqlite3 db2 test.db2 + sqlite3changeset_apply db2 $C "" + uplevel do_test $tn.1 [list {execsql { PRAGMA integrity_check } db2}] ok + db2 close + + set cksum [scksum db main] + uplevel do_test $tn.2 [list {scksum db aux}] [list $cksum] +} diff --git a/ext/session/sessionrebase.test b/ext/session/sessionrebase.test index cdf3322838..033348f9ce 100644 --- a/ext/session/sessionrebase.test +++ b/ext/session/sessionrebase.test @@ -84,6 +84,7 @@ proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} { db eval BEGIN sqlite3session S1 db main + S1 object_config rowid 1 S1 attach * execsql $sql1 db set c1 [S1 changeset] @@ -91,6 +92,7 @@ proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} { if {$i==1} { sqlite3session S2 db2 main + S2 object_config rowid 1 S2 attach * execsql $sql2 db2 set c2 [S2 changeset] @@ -100,6 +102,7 @@ proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} { foreach sql [split $sql2 ";"] { if {[string is space $sql]} continue sqlite3session S2 db2 main + S2 object_config rowid 1 S2 attach * execsql $sql db2 lappend c2 [S2 changeset] @@ -341,6 +344,79 @@ do_rebase_test 2.2.3 { OMIT } { SELECT * FROM t2 WHERE z='B' } { 1 one B } + +reset_db +do_execsql_test 2.3.0 { + CREATE TABLE t1 (b TEXT); + INSERT INTO t1(rowid, b) VALUES(1, 'one'); + INSERT INTO t1(rowid, b) VALUES(2, 'two'); + INSERT INTO t1(rowid, b) VALUES(3, 'three'); +} +do_rebase_test 2.3.1 { + UPDATE t1 SET b = 'two.1' WHERE rowid=2 +} { + UPDATE t1 SET b = 'two.2' WHERE rowid=2; +} { + OMIT +} { SELECT rowid, * FROM t1 } {1 one 2 two.1 3 three} + +do_rebase_test 2.3.2 { + UPDATE t1 SET b = 'two.1' WHERE rowid=2 +} { + UPDATE t1 SET b = 'two.2' WHERE rowid=2; +} { + REPLACE +} { SELECT rowid, * FROM t1 } {1 one 2 two.2 3 three} + +do_rebase_test 2.3.3 { + DELETE FROM t1 WHERE rowid=3 +} { + DELETE FROM t1 WHERE rowid=3; +} { + OMIT +} { SELECT rowid, * FROM t1 } {1 one 2 two} + +do_rebase_test 2.3.4 { + DELETE FROM t1 WHERE rowid=1 +} { + UPDATE t1 SET b='one.2' WHERE rowid=1 +} { + OMIT +} { SELECT rowid, * FROM t1 } {2 two 3 three} + +do_rebase_test 2.3.6 { + UPDATE t1 SET b='three.1' WHERE rowid=3 +} { + DELETE FROM t1 WHERE rowid=3; +} { + OMIT +} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three.1} + +do_rebase_test 2.3.7 { + UPDATE t1 SET b='three.1' WHERE rowid=3 +} { + DELETE FROM t1 WHERE rowid=3; +} { + REPLACE +} { SELECT rowid, * FROM t1 } {1 one 2 two} + +do_rebase_test 2.3.8 { + INSERT INTO t1(rowid, b) VALUES(4, 'four.1') +} { + INSERT INTO t1(rowid, b) VALUES(4, 'four.2'); +} { + REPLACE +} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.2} + +do_rebase_test 2.3.9 { + INSERT INTO t1(rowid, b) VALUES(4, 'four.1') +} { + INSERT INTO t1(rowid, b) VALUES(4, 'four.2'); +} { + OMIT +} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.1} + + #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { diff --git a/ext/session/sessionrowid.test b/ext/session/sessionrowid.test new file mode 100644 index 0000000000..14af90acef --- /dev/null +++ b/ext/session/sessionrowid.test @@ -0,0 +1,281 @@ +# 2011 Mar 16 +# +# 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. +# +#*********************************************************************** +# +# The focus of this file is testing the session module. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] session_common.tcl] +source $testdir/tester.tcl +ifcapable !session {finish_test; return} + +set testprefix sessionrowid + +do_execsql_test 0.0 { + CREATE TABLE t1(a, b); +} + +foreach {tn rowid bEmpty} { + 1 0 1 + 2 1 0 + 3 -1 1 +} { + do_test 0.$tn { + sqlite3session S db main + if {$rowid>=0} { S object_config rowid $rowid } + S attach t1 + execsql { INSERT INTO t1 VALUES(1, 2); } + expr [string length [S changeset]]==0 + } $bEmpty + S delete +} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); +} + +do_iterator_test 1.1 t1 { + INSERT INTO t1 VALUES('i', 'one'); +} { + {INSERT t1 0 X.. {} {i 1 t i t one}} +} + +do_execsql_test 1.2 { + SELECT rowid, * FROM t1 +} {1 i one} + +do_iterator_test 1.3 t1 { + UPDATE t1 SET b='two' +} { + {UPDATE t1 0 X.. {i 1 {} {} t one} {{} {} {} {} t two}} +} + +do_iterator_test 1.4 t1 { + DELETE FROM t1; +} { + {DELETE t1 0 X.. {i 1 t i t two} {}} +} + +do_iterator_test 1.5 t1 { + INSERT INTO t1(rowid, a, b) VALUES(14, 'hello', 'world'); + INSERT INTO t1(rowid, a, b) VALUES(NULL, 'yes', 'no'); + INSERT INTO t1(rowid, a, b) VALUES(-123, 'ii', 'iii'); +} { + {INSERT t1 0 X.. {} {i -123 t ii t iii}} + {INSERT t1 0 X.. {} {i 15 t yes t no}} + {INSERT t1 0 X.. {} {i 14 t hello t world}} +} + +do_iterator_test 1.6 t1 { + UPDATE t1 SET a='deluxe' WHERE rowid=14; + DELETE FROM t1 WHERE rowid=-123; + INSERT INTO t1 VALUES('x', 'xi'); +} { + {DELETE t1 0 X.. {i -123 t ii t iii} {}} + {UPDATE t1 0 X.. {i 14 t hello {} {}} {{} {} t deluxe {} {}}} + {INSERT t1 0 X.. {} {i 16 t x t xi}} +} + +#------------------------------------------------------------------------- +reset_db +forcedelete test.db2 +sqlite3 db2 test.db2 + +do_execsql_test 2.0 { + CREATE TABLE t1(a, b); +} +do_execsql_test -db db2 2.0.1 { + CREATE TABLE t1(a, b); +} + +proc xConflict {args} { + puts "CONFLICT!" + return "OMIT" +} + +do_test 2.1 { + set C [changeset_from_sql { + INSERT INTO t1 VALUES('abc', 'def'); + }] + sqlite3changeset_apply db2 $C xConflict + execsql { SELECT * FROM t1 } db2 +} {abc def} +do_test 2.2 { + set C [changeset_from_sql { + UPDATE t1 SET b='hello' + }] + sqlite3changeset_apply db2 $C xConflict + execsql { SELECT * FROM t1 } db2 +} {abc hello} +do_test 2.3 { + set C [changeset_from_sql { + DELETE FROM t1 WHERE b='hello' + }] + sqlite3changeset_apply db2 $C xConflict + execsql { SELECT * FROM t1 } db2 +} {} + +do_test 2.4 { + do_then_apply_sql { + INSERT INTO t1 VALUES('i', 'one'); + INSERT INTO t1 VALUES('ii', 'two'); + INSERT INTO t1 VALUES('iii', 'three'); + INSERT INTO t1 VALUES('iv', 'four'); + } + compare_db db db2 +} {} + +do_test 2.5 { + do_then_apply_sql { + DELETE FROM t1 WHERE a='ii'; + UPDATE t1 SET b='THREE' WHERE a='iii'; + UPDATE t1 SET a='III' WHERE a='iii'; + INSERT INTO t1 VALUES('v', 'five'); + } + compare_db db db2 +} {} + +do_execsql_test 2.6 {SELECT * FROM t1} {i one III THREE iv four v five} +do_execsql_test -db db2 2.7 {SELECT * FROM t1} {i one III THREE iv four v five} + +#------------------------------------------------------------------------- +db2 close +reset_db +forcedelete test.db2 +sqlite3 db2 test.db2 + +set init_sql { + CREATE TABlE t4(a, b); + CREATE INDEX t4a ON t4(a); + CREATE UNIQUE INDEX t4b ON t4(b); +} + +do_execsql_test 3.0 $init_sql +do_execsql_test -db db2 3.0a $init_sql + +do_execsql_test -db db2 3.1 { + INSERT INTO t4(rowid, a, b) VALUES(43, 'hello', 'world'); +} +do_conflict_test 3.2 -sql { + INSERT INTO t4(rowid, a, b) VALUES(43, 'abc', 'def'); +} -tables t4 -conflicts { + {INSERT t4 CONFLICT {i 43 t abc t def} {i 43 t hello t world}} +} +do_execsql_test -db db2 3.3 { + SELECT * FROM t4 +} {hello world} + +do_execsql_test 3.4 { DELETE FROM t4 } +do_conflict_test 3.5 -sql { + INSERT INTO t4(rowid, a, b) VALUES(43, 'abc', 'def'); +} -tables t4 -conflicts { + {INSERT t4 CONFLICT {i 43 t abc t def} {i 43 t hello t world}} +} -policy REPLACE +do_execsql_test -db db2 3.6 { + SELECT * FROM t4 +} {abc def} + +do_execsql_test 3.7 { DELETE FROM t4 } +do_conflict_test 3.8 -sql { + INSERT INTO t4(rowid, a, b) VALUES(45, 'xyz', 'def'); +} -tables t4 -conflicts { + {INSERT t4 CONSTRAINT {i 45 t xyz t def}} +} +do_execsql_test -db db2 3.9 { + SELECT * FROM t4 +} {abc def} + + +do_execsql_test -db db 3.10a { DELETE FROM t4 } +do_execsql_test -db db2 3.10b { DELETE FROM t4 } + +do_execsql_test -db db 3.11a { + INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'one'); + INSERT INTO t4(rowid, a, b) VALUES(222, 'two', 'two'); +} +do_execsql_test -db db2 3.11b { + INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'blip'); +} + +do_conflict_test 3.12 -sql { + DELETE FROM t4 WHERE a='one'; +} -tables t4 -conflicts { + {DELETE t4 DATA {i 111 t one t one} {i 111 t one t blip}} +} +do_execsql_test -db db2 3.13 { + SELECT * FROM t4 +} {one blip} + +do_conflict_test 3.14 -sql { + DELETE FROM t4 WHERE a='two'; +} -tables t4 -conflicts { + {DELETE t4 NOTFOUND {i 222 t two t two}} +} +do_execsql_test -db db2 3.15 { + SELECT * FROM t4 +} {one blip} + +do_execsql_test -db db 3.16a { DELETE FROM t4 } +do_execsql_test -db db2 3.16b { DELETE FROM t4 } + +do_execsql_test -db db 3.17a { + INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'one'); + INSERT INTO t4(rowid, a, b) VALUES(222, 'two', 'two'); +} +do_execsql_test -db db2 3.17b { + INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'blip'); +} + +do_conflict_test 3.18 -sql { + UPDATE t4 SET b='xyz' WHERE a='one' +} -tables t4 -conflicts { + {UPDATE t4 DATA {i 111 {} {} t one} {{} {} {} {} t xyz} {i 111 t one t blip}} +} +do_execsql_test -db db2 3.19 { + SELECT * FROM t4 +} {one blip} + +do_conflict_test 3.20 -sql { + UPDATE t4 SET b='123' WHERE a='two' +} -tables t4 -conflicts { + {UPDATE t4 NOTFOUND {i 222 {} {} t two} {{} {} {} {} t 123}} +} +do_execsql_test -db db2 3.21 { + SELECT * FROM t4 +} {one blip} + +#-------------------------------------------------------------------------- +breakpoint +do_diff_test 4.0 { + CREATE TABLE t1(x, y); + CREATE TABLE aux.t1(x, y); + INSERT INTO t1 VALUES(1, 2); +} + +do_diff_test 4.1 { + CREATE TABLE t1(x, y); + CREATE TABLE aux.t1(x, y); + INSERT INTO aux.t1 VALUES(1, 2); +} + +do_diff_test 4.2 { + CREATE TABLE t1(x, y); + CREATE TABLE aux.t1(x, y); + INSERT INTO t1(rowid, x, y) VALUES(413, 'hello', 'there'); + INSERT INTO aux.t1(rowid, x, y) VALUES(413, 'hello', 'world'); +} + +finish_test + diff --git a/ext/session/sessionsize.test b/ext/session/sessionsize.test index 04d05514db..01638c6677 100644 --- a/ext/session/sessionsize.test +++ b/ext/session/sessionsize.test @@ -113,17 +113,17 @@ do_execsql_test 3.0 { do_test 3.1 { sqlite3session S db main - S object_config_size -1 + S object_config size -1 } 1 -do_test 3.2.1 { S object_config_size 0 } 0 -do_test 3.2.2 { S object_config_size -1 } 0 -do_test 3.2.3 { S object_config_size 1 } 1 -do_test 3.2.4 { S object_config_size -1 } 1 +do_test 3.2.1 { S object_config size 0 } 0 +do_test 3.2.2 { S object_config size -1 } 0 +do_test 3.2.3 { S object_config size 1 } 1 +do_test 3.2.4 { S object_config size -1 } 1 do_test 3.3 { S attach t1 } {} -do_test 3.4 { S object_config_size 1 } {SQLITE_MISUSE} -do_test 3.4 { S object_config_size -1 } {1} +do_test 3.4 { S object_config size 1 } {SQLITE_MISUSE} +do_test 3.4 { S object_config size -1 } {1} S delete diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 225d0316a8..e601a4ae7a 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -25,6 +25,8 @@ typedef struct SessionInput SessionInput; # endif #endif +#define SESSIONS_ROWID "_rowid_" + static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE; typedef struct SessionHook SessionHook; @@ -46,6 +48,7 @@ struct sqlite3_session { int bEnable; /* True if currently recording */ int bIndirect; /* True if all changes are indirect */ int bAutoAttach; /* True to auto-attach tables */ + int bImplicitPK; /* True to handle tables with implicit PK */ int rc; /* Non-zero if an error has occurred */ void *pFilterCtx; /* First argument to pass to xTableFilter */ int (*xTableFilter)(void *pCtx, const char *zTab); @@ -122,6 +125,7 @@ struct SessionTable { char *zName; /* Local name of table */ int nCol; /* Number of columns in table zName */ int bStat1; /* True if this is sqlite_stat1 */ + int bRowid; /* True if this table uses rowid for PK */ const char **azCol; /* Column names */ u8 *abPK; /* Array of primary key flags */ int nEntry; /* Total number of entries in hash table */ @@ -514,6 +518,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){ */ static int sessionPreupdateHash( sqlite3_session *pSession, /* Session object that owns pTab */ + i64 iRowid, SessionTable *pTab, /* Session table handle */ int bNew, /* True to hash the new.* PK */ int *piHash, /* OUT: Hash value */ @@ -522,48 +527,53 @@ static int sessionPreupdateHash( unsigned int h = 0; /* Hash value to return */ int i; /* Used to iterate through columns */ - assert( *pbNullPK==0 ); - assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); - for(i=0; inCol; i++){ - if( pTab->abPK[i] ){ - int rc; - int eType; - sqlite3_value *pVal; + if( pTab->bRowid ){ + assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) ); + h = sessionHashAppendI64(h, iRowid); + }else{ + assert( *pbNullPK==0 ); + assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); + for(i=0; inCol; i++){ + if( pTab->abPK[i] ){ + int rc; + int eType; + sqlite3_value *pVal; - if( bNew ){ - rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); - }else{ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); - } - if( rc!=SQLITE_OK ) return rc; + if( bNew ){ + rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); + }else{ + rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); + } + if( rc!=SQLITE_OK ) return rc; - eType = sqlite3_value_type(pVal); - h = sessionHashAppendType(h, eType); - if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - i64 iVal; - if( eType==SQLITE_INTEGER ){ - iVal = sqlite3_value_int64(pVal); + eType = sqlite3_value_type(pVal); + h = sessionHashAppendType(h, eType); + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + i64 iVal; + if( eType==SQLITE_INTEGER ){ + iVal = sqlite3_value_int64(pVal); + }else{ + double rVal = sqlite3_value_double(pVal); + assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); + memcpy(&iVal, &rVal, 8); + } + h = sessionHashAppendI64(h, iVal); + }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ + const u8 *z; + int n; + if( eType==SQLITE_TEXT ){ + z = (const u8 *)sqlite3_value_text(pVal); + }else{ + z = (const u8 *)sqlite3_value_blob(pVal); + } + n = sqlite3_value_bytes(pVal); + if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; + h = sessionHashAppendBlob(h, n, z); }else{ - double rVal = sqlite3_value_double(pVal); - assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); - memcpy(&iVal, &rVal, 8); + assert( eType==SQLITE_NULL ); + assert( pTab->bStat1==0 || i!=1 ); + *pbNullPK = 1; } - h = sessionHashAppendI64(h, iVal); - }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ - const u8 *z; - int n; - if( eType==SQLITE_TEXT ){ - z = (const u8 *)sqlite3_value_text(pVal); - }else{ - z = (const u8 *)sqlite3_value_blob(pVal); - } - n = sqlite3_value_bytes(pVal); - if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; - h = sessionHashAppendBlob(h, n, z); - }else{ - assert( eType==SQLITE_NULL ); - assert( pTab->bStat1==0 || i!=1 ); - *pbNullPK = 1; } } } @@ -846,6 +856,7 @@ static int sessionMergeUpdate( */ static int sessionPreupdateEqual( sqlite3_session *pSession, /* Session object that owns SessionTable */ + i64 iRowid, /* Rowid value if pTab->bRowid */ SessionTable *pTab, /* Table associated with change */ SessionChange *pChange, /* Change to compare to */ int op /* Current pre-update operation */ @@ -853,6 +864,11 @@ static int sessionPreupdateEqual( int iCol; /* Used to iterate through columns */ u8 *a = pChange->aRecord; /* Cursor used to scan change record */ + if( pTab->bRowid ){ + if( a[0]!=SQLITE_INTEGER ) return 0; + return sessionGetI64(&a[1])==iRowid; + } + assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); for(iCol=0; iColnCol; iCol++){ if( !pTab->abPK[iCol] ){ @@ -997,7 +1013,8 @@ static int sessionTableInfo( int *pnCol, /* OUT: number of columns */ const char **pzTab, /* OUT: Copy of zThis */ const char ***pazCol, /* OUT: Array of column names for table */ - u8 **pabPK /* OUT: Array of booleans - true for PK col */ + u8 **pabPK, /* OUT: Array of booleans - true for PK col */ + int *pbRowid /* OUT: True if only PK is a rowid */ ){ char *zPragma; sqlite3_stmt *pStmt; @@ -1009,6 +1026,7 @@ static int sessionTableInfo( u8 *pAlloc = 0; char **azCol = 0; u8 *abPK = 0; + int bRowid = 0; /* Set to true to use rowid as PK */ assert( pazCol && pabPK ); @@ -1053,10 +1071,15 @@ static int sessionTableInfo( } nByte = nThis + 1; + bRowid = (pbRowid!=0); while( SQLITE_ROW==sqlite3_step(pStmt) ){ nByte += sqlite3_column_bytes(pStmt, 1); nDbCol++; + if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; } + if( nDbCol==0 ) bRowid = 0; + nDbCol += bRowid; + nByte += strlen(SESSIONS_ROWID); rc = sqlite3_reset(pStmt); if( rc==SQLITE_OK ){ @@ -1078,6 +1101,14 @@ static int sessionTableInfo( } i = 0; + if( bRowid ){ + int nName = strlen(SESSIONS_ROWID); + memcpy(pAlloc, SESSIONS_ROWID, nName+1); + azCol[i] = (char*)pAlloc; + pAlloc += nName+1; + abPK[i] = 1; + i++; + } while( SQLITE_ROW==sqlite3_step(pStmt) ){ int nName = sqlite3_column_bytes(pStmt, 1); const unsigned char *zName = sqlite3_column_text(pStmt, 1); @@ -1089,7 +1120,6 @@ static int sessionTableInfo( i++; } rc = sqlite3_reset(pStmt); - } /* If successful, populate the output variables. Otherwise, zero them and @@ -1106,6 +1136,7 @@ static int sessionTableInfo( if( pzTab ) *pzTab = 0; sessionFree(pSession, azCol); } + if( pbRowid ) *pbRowid = bRowid; sqlite3_finalize(pStmt); return rc; } @@ -1127,7 +1158,8 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK + pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK, + (pSession->bImplicitPK ? &pTab->bRowid : 0) ); if( pSession->rc==SQLITE_OK ){ int i; @@ -1199,6 +1231,7 @@ static int sessionUpdateMaxSize( ){ i64 nNew = 2; if( pC->op==SQLITE_INSERT ){ + if( pTab->bRowid ) nNew += 9; if( op!=SQLITE_DELETE ){ int ii; for(ii=0; iinCol; ii++){ @@ -1215,7 +1248,11 @@ static int sessionUpdateMaxSize( }else{ int ii; u8 *pCsr = pC->aRecord; - for(ii=0; iinCol; ii++){ + if( pTab->bRowid ){ + nNew += 9; + pCsr += 9; + } + for(ii=0; ii<(pTab->nCol-pTab->bRowid); ii++){ int bChanged = 1; int nOld = 0; int eType; @@ -1299,6 +1336,7 @@ static int sessionUpdateMaxSize( */ static void sessionPreupdateOneChange( int op, /* One of SQLITE_UPDATE, INSERT, DELETE */ + i64 iRowid, sqlite3_session *pSession, /* Session object pTab is attached to */ SessionTable *pTab /* Table that change applies to */ ){ @@ -1314,7 +1352,7 @@ static void sessionPreupdateOneChange( /* Check the number of columns in this xPreUpdate call matches the ** number of columns in the table. */ - if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ + if( (pTab->nCol-pTab->bRowid)!=pSession->hook.xCount(pSession->hook.pCtx) ){ pSession->rc = SQLITE_SCHEMA; return; } @@ -1347,14 +1385,16 @@ static void sessionPreupdateOneChange( /* Calculate the hash-key for this change. If the primary key of the row ** includes a NULL value, exit early. Such changes are ignored by the ** session module. */ - rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull); + rc = sessionPreupdateHash( + pSession, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull + ); if( rc!=SQLITE_OK ) goto error_out; if( bNull==0 ){ /* Search the hash table for an existing record for this row. */ SessionChange *pC; for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){ - if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break; + if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break; } if( pC==0 ){ @@ -1369,7 +1409,7 @@ static void sessionPreupdateOneChange( /* Figure out how large an allocation is required */ nByte = sizeof(SessionChange); - for(i=0; inCol; i++){ + for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p); @@ -1384,6 +1424,9 @@ static void sessionPreupdateOneChange( rc = sessionSerializeValue(0, p, &nByte); if( rc!=SQLITE_OK ) goto error_out; } + if( pTab->bRowid ){ + nByte += 9; /* Size of rowid field - an integer */ + } /* Allocate the change object */ pC = (SessionChange *)sessionMalloc64(pSession, nByte); @@ -1400,7 +1443,12 @@ static void sessionPreupdateOneChange( ** required values and encodings have already been cached in memory. ** It is not possible for an OOM to occur in this block. */ nByte = 0; - for(i=0; inCol; i++){ + if( pTab->bRowid ){ + pC->aRecord[0] = SQLITE_INTEGER; + sessionPutI64(&pC->aRecord[1], iRowid); + nByte = 9; + } + for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ pSession->hook.xOld(pSession->hook.pCtx, i, &p); @@ -1515,9 +1563,10 @@ static void xPreUpdate( pSession->rc = sessionFindTable(pSession, zName, &pTab); if( pTab ){ assert( pSession->rc==SQLITE_OK ); - sessionPreupdateOneChange(op, pSession, pTab); + assert( op==SQLITE_UPDATE || iKey1==iKey2 ); + sessionPreupdateOneChange(op, iKey1, pSession, pTab); if( op==SQLITE_UPDATE ){ - sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab); + sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab); } } } @@ -1556,6 +1605,7 @@ static void sessionPreupdateHooks( typedef struct SessionDiffCtx SessionDiffCtx; struct SessionDiffCtx { sqlite3_stmt *pStmt; + int bRowid; int nOldOff; }; @@ -1564,17 +1614,17 @@ struct SessionDiffCtx { */ static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff); + *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid); return SQLITE_OK; } static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - *ppVal = sqlite3_column_value(p->pStmt, iVal); + *ppVal = sqlite3_column_value(p->pStmt, iVal+p->bRowid); return SQLITE_OK; } static int sessionDiffCount(void *pCtx){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); + return (p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt)) - p->bRowid; } static int sessionDiffDepth(void *pCtx){ (void)pCtx; @@ -1653,14 +1703,16 @@ static char *sessionExprCompareOther( static char *sessionSelectFindNew( const char *zDb1, /* Pick rows in this db only */ const char *zDb2, /* But not in this one */ + int bRowid, const char *zTbl, /* Table name */ const char *zExpr ){ + const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*"); char *zRet = sqlite3_mprintf( - "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS (" + "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS (" " SELECT 1 FROM \"%w\".\"%w\" WHERE %s" ")", - zDb1, zTbl, zDb2, zTbl, zExpr + zSel, zDb1, zTbl, zDb2, zTbl, zExpr ); return zRet; } @@ -1674,7 +1726,9 @@ static int sessionDiffFindNew( char *zExpr ){ int rc = SQLITE_OK; - char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr); + char *zStmt = sessionSelectFindNew( + zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr + ); if( zStmt==0 ){ rc = SQLITE_NOMEM; @@ -1685,8 +1739,10 @@ static int sessionDiffFindNew( SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; pDiffCtx->pStmt = pStmt; pDiffCtx->nOldOff = 0; + pDiffCtx->bRowid = pTab->bRowid; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - sessionPreupdateOneChange(op, pSession, pTab); + i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0); + sessionPreupdateOneChange(op, iRowid, pSession, pTab); } rc = sqlite3_finalize(pStmt); } @@ -1696,6 +1752,27 @@ static int sessionDiffFindNew( return rc; } +/* +** Return a comma-separated list of the fully-qualified (with both database +** and table name) column names from table pTab. e.g. +** +** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c" +*/ +static char *sessionAllCols( + const char *zDb, + SessionTable *pTab +){ + int ii; + char *zRet = 0; + for(ii=0; iinCol; ii++){ + zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"%s", + zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii] + ); + if( !zRet ) break; + } + return zRet; +} + static int sessionDiffFindModified( sqlite3_session *pSession, SessionTable *pTab, @@ -1710,11 +1787,13 @@ static int sessionDiffFindModified( if( zExpr2==0 ){ rc = SQLITE_NOMEM; }else{ + char *z1 = sessionAllCols(pSession->zDb, pTab); + char *z2 = sessionAllCols(zFrom, pTab); char *zStmt = sqlite3_mprintf( - "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)", - pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2 + "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)", + z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2 ); - if( zStmt==0 ){ + if( zStmt==0 || z1==0 || z2==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; @@ -1725,12 +1804,15 @@ static int sessionDiffFindModified( pDiffCtx->pStmt = pStmt; pDiffCtx->nOldOff = pTab->nCol; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab); + i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0); + sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab); } rc = sqlite3_finalize(pStmt); } - sqlite3_free(zStmt); } + sqlite3_free(zStmt); + sqlite3_free(z1); + sqlite3_free(z2); } return rc; @@ -1769,9 +1851,12 @@ int sqlite3session_diff( int bHasPk = 0; int bMismatch = 0; int nCol; /* Columns in zFrom.zTbl */ + int bRowid = 0; u8 *abPK; const char **azCol = 0; - rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK); + rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK, + pSession->bImplicitPK ? &bRowid : 0 + ); if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ bMismatch = 1; @@ -2422,6 +2507,7 @@ static int sessionSelectStmt( int bIgnoreNoop, const char *zDb, /* Database name */ const char *zTab, /* Table name */ + int bRowid, int nCol, /* Number of columns in table */ const char **azCol, /* Names of table columns */ u8 *abPK, /* PRIMARY KEY array */ @@ -2430,7 +2516,7 @@ static int sessionSelectStmt( int rc = SQLITE_OK; char *zSql = 0; const char *zSep = ""; - const char *zCols = "*"; + const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*"; int nSql = -1; int i; @@ -2449,7 +2535,6 @@ static int sessionSelectStmt( zCols = "tbl, ?2, stat"; }else{ for(i=0; izDb, zName, &nCol, 0,&azCol,&abPK); - if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ + rc = sessionTableInfo( + 0, db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK, + (pSession->bImplicitPK ? &bRowid : 0) + ); + if( rc==SQLITE_OK && ( + pTab->nCol!=nCol + || pTab->bRowid!=bRowid + || memcmp(abPK, pTab->abPK, nCol) + )){ rc = SQLITE_SCHEMA; } @@ -2669,7 +2762,7 @@ static int sessionGenerateChangeset( /* Build and compile a statement to execute: */ if( rc==SQLITE_OK ){ rc = sessionSelectStmt( - db, 0, pSession->zDb, zName, nCol, azCol, abPK, &pSel + db, 0, pSession->zDb, zName, bRowid, nCol, azCol, abPK, &pSel ); } @@ -2753,8 +2846,8 @@ int sqlite3session_changeset( int rc; if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE; - rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset); - assert( rc || pnChangeset==0 + rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset); + assert( 1 || rc || pnChangeset==0 || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize ); return rc; @@ -2871,6 +2964,19 @@ int sqlite3session_object_config(sqlite3_session *pSession, int op, void *pArg){ break; } + case SQLITE_SESSION_OBJCONFIG_ROWID: { + int iArg = *(int*)pArg; + if( iArg>=0 ){ + if( pSession->pTable ){ + rc = SQLITE_MISUSE; + }else{ + pSession->bImplicitPK = (iArg!=0); + } + } + *(int*)pArg = pSession->bImplicitPK; + break; + } + default: rc = SQLITE_MISUSE; } @@ -3860,6 +3966,7 @@ struct SessionApplyCtx { u8 bRebaseStarted; /* If table header is already in rebase */ u8 bRebase; /* True to collect rebase information */ u8 bIgnoreNoop; /* True to ignore no-op conflicts */ + int bRowid; }; /* Number of prepared UPDATE statements to cache. */ @@ -4110,8 +4217,9 @@ static int sessionSelectRow( const char *zTab, /* Table name */ SessionApplyCtx *p /* Session changeset-apply context */ ){ + /* TODO */ return sessionSelectStmt(db, p->bIgnoreNoop, - "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect + "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect ); } @@ -4807,6 +4915,7 @@ static int sessionChangesetApply( sApply.bStat1 = 0; sApply.bDeferConstraints = 1; sApply.bRebaseStarted = 0; + sApply.bRowid = 0; memset(&sApply.constraints, 0, sizeof(SessionBuffer)); /* If an xFilter() callback was specified, invoke it now. If the @@ -4826,8 +4935,8 @@ static int sessionChangesetApply( int i; sqlite3changeset_pk(pIter, &abPK, 0); - rc = sessionTableInfo(0, - db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK + rc = sessionTableInfo(0, db, "main", zNew, + &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK, &sApply.bRowid ); if( rc!=SQLITE_OK ) break; for(i=0; iSQLITE_SESSION_OBJCONFIG_ROWID
+** This option is used to set, clear or query the flag that enables +** collection of data for tables with no explicit PRIMARY KEY. +** +** Normally, tables with no explicit PRIMARY KEY are simply ignored +** by the sessions module. However, if this flag is set, it behaves +** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted +** as their leftmost columns. +** +** It is an error (SQLITE_MISUSE) to attempt to modify this setting after +** the first table has been attached to the session object. */ int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); /* */ -#define SQLITE_SESSION_OBJCONFIG_SIZE 1 +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 +#define SQLITE_SESSION_OBJCONFIG_ROWID 2 /* ** CAPI3REF: Enable Or Disable A Session Object diff --git a/ext/session/test_session.c b/ext/session/test_session.c index f10afe03f6..0836238b5d 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -76,9 +76,11 @@ int sql_exec_changeset( ){ sqlite3_session *pSession = 0; int rc; + int val = 1; /* Create a new session object */ rc = sqlite3session_create(db, "main", &pSession); + sqlite3session_object_config(pSession, SQLITE_SESSION_OBJCONFIG_ROWID, &val); /* Configure the session object to record changes to all tables */ if( rc==SQLITE_OK ) rc = sqlite3session_attach(pSession, NULL); @@ -260,7 +262,7 @@ static int SQLITE_TCLAPI test_session_cmd( { "diff", 2, "FROMDB TBL", }, /* 8 */ { "memory_used", 0, "", }, /* 9 */ { "changeset_size", 0, "", }, /* 10 */ - { "object_config_size", 1, "INTEGER", }, /* 11 */ + { "object_config", 2, "OPTION INTEGER", }, /* 11 */ { 0 } }; int iSub; @@ -379,15 +381,27 @@ static int SQLITE_TCLAPI test_session_cmd( Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize)); break; } - case 11: { + case 11: { /* object_config */ + struct ObjConfOpt { + const char *zName; + int opt; + } aOpt[] = { + { "size", SQLITE_SESSION_OBJCONFIG_SIZE }, + { "rowid", SQLITE_SESSION_OBJCONFIG_ROWID }, + { 0, 0 } + }; + size_t sz = sizeof(aOpt[0]); + int rc; int iArg; - if( Tcl_GetIntFromObj(interp, objv[2], &iArg) ){ + int iOpt; + if( Tcl_GetIndexFromObjStruct(interp,objv[2],aOpt,sz,"option",0,&iOpt) ){ return TCL_ERROR; } - rc = sqlite3session_object_config( - pSession, SQLITE_SESSION_OBJCONFIG_SIZE, &iArg - ); + if( Tcl_GetIntFromObj(interp, objv[3], &iArg) ){ + return TCL_ERROR; + } + rc = sqlite3session_object_config(pSession, aOpt[iOpt].opt, &iArg); if( rc!=SQLITE_OK ){ extern const char *sqlite3ErrName(int); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); diff --git a/manifest b/manifest index a40d72211a..7b5292db51 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\snote\sabout\sthe\sjournaling\smode\sin\sthe\sOPFS\sVFS.\sNo\scode\schanges. -D 2023-04-24T04:25:42.837 +C Allow\sthe\ssessions\smodule\sto\sbe\sconfigured\sto\scapture\schanges\sfrom\stables\swith\sno\sexplicit\sPRIMARY\sKEY. +D 2023-04-24T19:22:21.668 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -449,12 +449,12 @@ F ext/session/session9.test 5409d90d8141881d08285ed1c2c0d8d10fb92069 F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f F ext/session/sessionB.test c4fb7f8a688787111606e123a555f18ee04f65bb9f2a4bb2aa71d55ce4e6d02c F ext/session/sessionC.test f8a5508bc059ae646e5ec9bdbca66ad24bc92fe99fda5790ac57e1f59fce2fdf -F ext/session/sessionD.test 4f91d0ca8afc4c3969c72c9f0b5ea9527e21de29039937d0d973f821e8470724 +F ext/session/sessionD.test f5c6a762d00bc6ca9d561695c322ba8ecca2bed370486707ef37cf565d2f6c73 F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d064bce83111d F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401 F ext/session/sessionG.test 3efe388282d641b65485b5462e67851002cd91a282dc95b685d085eb8efdad0a F ext/session/sessionH.test 71bbff6b1abb2c4ac62b84dee53273c37e0b21e5fde3aed80929403e091ef859 -F ext/session/session_common.tcl db0dda567c75950604072251744e9a6ad5795a3009963c44eb8510f23a8cda64 +F ext/session/session_common.tcl e5598096425486b363718e2cda48ee85d660c96b4f8ea9d9d7a4c3ef514769da F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3 F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf @@ -465,13 +465,14 @@ F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2 F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09 F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7 F ext/session/sessionnoop2.test 5c9a882219e54711c98dccd2fd81392f189a59325e4fb5d8ed25e33a0c2f0ba2 -F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810 -F ext/session/sessionsize.test 6f644aff31c7f1e4871e9ff3542766e18da68fc7e587b83a347ea9820a002dd8 +F ext/session/sessionrebase.test 702378bdcb5062f1106e74457beca8797d09c113a81768734a58b197b5b334e2 +F ext/session/sessionrowid.test 6323ba831721205fd729929745038fd54e9d128c66c654b8d0b26853095a321c +F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795 F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc -F ext/session/sqlite3session.c 1795263b72c1a17e48e95a131a69543af3fa31aa8e81271c7c5cb0911f063604 -F ext/session/sqlite3session.h c367c3043dbb57f69cca35258ebbeadb24e8738980b1a1ae1e281c1b0fac3989 -F ext/session/test_session.c b55a669a2150eb7c491b8b42c69a3eed9bc895cf5fea371a2c813b9618f72163 +F ext/session/sqlite3session.c a0d7d71f9b111e443b53afc49b6cb5ccf48734af216c91dbe6640b7e4cd8c740 +F ext/session/sqlite3session.h 24299a3b64f11afc4422ce92d030ffdb2d3181851a1763b4a0432e195b2a8a16 +F ext/session/test_session.c 5285482f83cd92b4c1fe12fcf88210566a18312f4f2aa110f6399dae46aeccbb F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb @@ -2059,8 +2060,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 17f5dd2d2ae02a95180b9208b7de805922ba20271d3263e3193f0d46f4ec324c -R 7c6f5a98ea12f09a60bc441886d297ed -U stephan -Z c684703beca8cd9cb5def7974649e125 +P e79c95fc130fc302719690eb6391d96070aff825b2b51ef6c4ad459d9a8918d7 +R 1829aad474dae92cc041c644553e0142 +T *branch * sessions-rowid-tables +T *sym-sessions-rowid-tables * +T -sym-trunk * +U dan +Z 7494f98659d6e6e0ecd97f2ba99a8ae6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 20ed04ba3a..87be73f74f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e79c95fc130fc302719690eb6391d96070aff825b2b51ef6c4ad459d9a8918d7 \ No newline at end of file +8a612f0860126c0c8473b1e65fcabb9a8821d8bf09fdf3f6018acfc99df9af71 \ No newline at end of file From 21461407f64ef6b81b3d76ab4a23f07ececd0c1d Mon Sep 17 00:00:00 2001 From: larrybr Date: Tue, 25 Apr 2023 02:44:53 +0000 Subject: [PATCH 02/16] Check for OOM sqlite_value_x() returns in base64, base85 extensions. FossilOrigin-Name: e6f9c0b1f963033a8e17d13935c5c6b12d263fe10c585035a3d1f1154c6ba5d6 --- ext/misc/base64.c | 18 ++++++++++++++++-- ext/misc/base85.c | 18 ++++++++++++++++-- manifest | 17 ++++++++--------- manifest.uuid | 2 +- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/ext/misc/base64.c b/ext/misc/base64.c index 4da3f43eb7..25e76a5e99 100644 --- a/ext/misc/base64.c +++ b/ext/misc/base64.c @@ -219,9 +219,16 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ sqlite3_result_error(context, "blob expanded to base64 too big", -1); return; } + bBuf = (u8*)sqlite3_value_blob(av[0]); + if( !bBuf ){ + if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ + goto memFail; + } + sqlite3_result_text(context,"",-1,SQLITE_STATIC); + break; + } cBuf = sqlite3_malloc(nc); if( !cBuf ) goto memFail; - bBuf = (u8*)sqlite3_value_blob(av[0]); nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf); sqlite3_result_text(context, cBuf, nc, sqlite3_free); break; @@ -234,9 +241,16 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ }else if( nb<1 ){ nb = 1; } + cBuf = (char *)sqlite3_value_text(av[0]); + if( !cBuf ){ + if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ + goto memFail; + } + sqlite3_result_zeroblob(context, 0); + break; + } bBuf = sqlite3_malloc(nb); if( !bBuf ) goto memFail; - cBuf = (char *)sqlite3_value_text(av[0]); nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf); sqlite3_result_blob(context, bBuf, nb, sqlite3_free); break; diff --git a/ext/misc/base85.c b/ext/misc/base85.c index 5ec136dbc6..8e7ea76311 100644 --- a/ext/misc/base85.c +++ b/ext/misc/base85.c @@ -297,9 +297,16 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ sqlite3_result_error(context, "blob expanded to base85 too big", -1); return; } + bBuf = (u8*)sqlite3_value_blob(av[0]); + if( !bBuf ){ + if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ + goto memFail; + } + sqlite3_result_text(context,"",-1,SQLITE_STATIC); + break; + } cBuf = sqlite3_malloc(nc); if( !cBuf ) goto memFail; - bBuf = (u8*)sqlite3_value_blob(av[0]); nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf); sqlite3_result_text(context, cBuf, nc, sqlite3_free); break; @@ -312,9 +319,16 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ }else if( nb<1 ){ nb = 1; } + cBuf = (char *)sqlite3_value_text(av[0]); + if( !cBuf ){ + if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ + goto memFail; + } + sqlite3_result_zeroblob(context, 0); + break; + } bBuf = sqlite3_malloc(nb); if( !bBuf ) goto memFail; - cBuf = (char *)sqlite3_value_text(av[0]); nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf); sqlite3_result_blob(context, bBuf, nb, sqlite3_free); break; diff --git a/manifest b/manifest index 0509728ae1..965038b25b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\scompile-time\sdetection\sof\sarchitecture\sbyte-order\sin\sthe\sRTREE\nextension\sso\sthat\sit\sis\saligned\swith\sthe\slatest\senhancements\sin\sthe\score. -D 2023-04-24T19:23:42.196 +C Check\sfor\sOOM\ssqlite_value_x()\sreturns\sin\sbase64,\sbase85\sextensions. +D 2023-04-25T02:44:53.418 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -271,8 +271,8 @@ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f23 F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358 F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824 -F ext/misc/base64.c e83a915fcb94c9332e9a92aa4c3beafe2552bd3da2813fc5fff31918cca0b834 -F ext/misc/base85.c 77dfd5813d23ea561d0348f922583888e78f8eaeb2b9a4a28226d092389890b8 +F ext/misc/base64.c 46e2a52e4c39b60c2b3be84001b603f9817dc90b2aba545942a1cda2b127f0be +F ext/misc/base85.c fed8e065a5eb01f70de57462dd488705cfe86120df28c39df1dad7c3470d8d89 F ext/misc/basexx.c 5e859e1820620aa8080fb9145eb47089de426ae808f6abb01a8e12921c3a8e67 F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9 @@ -2059,9 +2059,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 e79c95fc130fc302719690eb6391d96070aff825b2b51ef6c4ad459d9a8918d7 -Q +491bd51da5e2069078d7295396d80d2ccdc3a5871714fef948076939174e6acd -R 0ddcb2c385e38b7edc9b293e66b74615 -U drh -Z 660ef923c98b6f83ec3ee30adf820b34 +P 122431d3a7267ec83768316ab146c0557fb6c0577a4a47ac6ed3d7aa6811ca9a +R 3428184709b95547abf99ded23dd44a2 +U larrybr +Z e09ba3c72f888e22a41c09e468a29a9d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 07be9e66cc..6af61fd070 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -122431d3a7267ec83768316ab146c0557fb6c0577a4a47ac6ed3d7aa6811ca9a \ No newline at end of file +e6f9c0b1f963033a8e17d13935c5c6b12d263fe10c585035a3d1f1154c6ba5d6 \ No newline at end of file From 38c2052767df63ced5b3d96c46844f6a8d28a86f Mon Sep 17 00:00:00 2001 From: larrybr Date: Tue, 25 Apr 2023 04:28:39 +0000 Subject: [PATCH 03/16] Handle newline-trimmed input TEXT correctly in base64, base85 UDFs. FossilOrigin-Name: 8f637aae23e6638c064a34262dcf16a3cdfd000fb1fa1b2a834b292fe6659408 --- ext/misc/base64.c | 6 +++--- ext/misc/base85.c | 6 +++--- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ext/misc/base64.c b/ext/misc/base64.c index 25e76a5e99..bc7a976abc 100644 --- a/ext/misc/base64.c +++ b/ext/misc/base64.c @@ -148,9 +148,9 @@ static char* toBase64( u8 *pIn, int nbIn, char *pOut ){ } /* Skip over text which is not base64 numeral(s). */ -static char * skipNonB64( char *s ){ +static char * skipNonB64( char *s, int nc ){ char c; - while( (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; + while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; return s; } @@ -159,7 +159,7 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){ if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; while( ncIn>0 && *pIn!=PAD_CHAR ){ static signed char nboi[] = { 0, 0, 1, 2, 3 }; - char *pUse = skipNonB64(pIn); + char *pUse = skipNonB64(pIn, ncIn); unsigned long qv = 0L; int nti, nbo, nac; ncIn -= (pUse - pIn); diff --git a/ext/misc/base85.c b/ext/misc/base85.c index 8e7ea76311..e7ef0a04c9 100644 --- a/ext/misc/base85.c +++ b/ext/misc/base85.c @@ -140,9 +140,9 @@ static u8 base85DigitValue( char c ){ #define B85_DARK_MAX 80 -static char * skipNonB85( char *s ){ +static char * skipNonB85( char *s, int nc ){ char c; - while( (c = *s) && !IS_B85(c) ) ++s; + while( nc-- > 0 && (c = *s) && !IS_B85(c) ) ++s; return s; } @@ -212,7 +212,7 @@ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){ if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; while( ncIn>0 ){ static signed char nboi[] = { 0, 0, 1, 2, 3, 4 }; - char *pUse = skipNonB85(pIn); + char *pUse = skipNonB85(pIn, ncIn); unsigned long qv = 0L; int nti, nbo; ncIn -= (pUse - pIn); diff --git a/manifest b/manifest index 965038b25b..3fc806927c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Check\sfor\sOOM\ssqlite_value_x()\sreturns\sin\sbase64,\sbase85\sextensions. -D 2023-04-25T02:44:53.418 +C Handle\snewline-trimmed\sinput\sTEXT\scorrectly\sin\sbase64,\sbase85\sUDFs. +D 2023-04-25T04:28:39.874 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -271,8 +271,8 @@ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f23 F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358 F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824 -F ext/misc/base64.c 46e2a52e4c39b60c2b3be84001b603f9817dc90b2aba545942a1cda2b127f0be -F ext/misc/base85.c fed8e065a5eb01f70de57462dd488705cfe86120df28c39df1dad7c3470d8d89 +F ext/misc/base64.c a71b131e50300c654a66c469a25b62874481f3d1cb3beb56aca9a68edd812e0d +F ext/misc/base85.c 073054111988db593ef5fdb87ab8c459df1ea0c3aaaddf0f5bfa3d72b7e6280a F ext/misc/basexx.c 5e859e1820620aa8080fb9145eb47089de426ae808f6abb01a8e12921c3a8e67 F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9 @@ -2059,8 +2059,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 122431d3a7267ec83768316ab146c0557fb6c0577a4a47ac6ed3d7aa6811ca9a -R 3428184709b95547abf99ded23dd44a2 +P e6f9c0b1f963033a8e17d13935c5c6b12d263fe10c585035a3d1f1154c6ba5d6 +R 7500f54b9a757a6bdf9e41121051af70 U larrybr -Z e09ba3c72f888e22a41c09e468a29a9d +Z e45f0a7f30148e18d14433c2a4564a3c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6af61fd070..a40e09b2de 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e6f9c0b1f963033a8e17d13935c5c6b12d263fe10c585035a3d1f1154c6ba5d6 \ No newline at end of file +8f637aae23e6638c064a34262dcf16a3cdfd000fb1fa1b2a834b292fe6659408 \ No newline at end of file From 0941ea8a62991ab5725ff729fd4d8cacce1434e1 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 25 Apr 2023 14:37:12 +0000 Subject: [PATCH 04/16] Avoid assuming that an expression in an ON() clause that evaluates to zero implies that the query will return zero rows when the query contains a RIGHT JOIN. [forum:95849acbe1|Forum Post 95849acbe1]. FossilOrigin-Name: 1783655ea422185e75593b89e4ef452a6f5496aefd389f88ce7fe4b7d41d6a98 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/where.c | 46 +++++++++++++++++++++++++++++++++++----------- test/joinH.test | 30 ++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 3fc806927c..39088ebefe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Handle\snewline-trimmed\sinput\sTEXT\scorrectly\sin\sbase64,\sbase85\sUDFs. -D 2023-04-25T04:28:39.874 +C Avoid\sassuming\sthat\san\sexpression\sin\san\sON()\sclause\sthat\sevaluates\sto\szero\simplies\sthat\sthe\squery\swill\sreturn\szero\srows\swhen\sthe\squery\scontains\sa\sRIGHT\sJOIN.\s[forum:95849acbe1|Forum\sPost\s95849acbe1]. +D 2023-04-25T14:37:12.443 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -717,7 +717,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 3f4ac276a60bda76f9f1f6f1c2c38599bacd4987e5efcd3f7fed2647bf97280a F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c ef9e644d1d76e86f68c941eb05d30a98fc0811eeef2a110906d81fedde81b6bf +F src/where.c 8899e22a397c839f551c8e1741c100ae2675feb0fe0a383d55816f2ca3d2b583 F src/whereInt.h e25203e5bfee149f5f1225ae0166cfb4f1e65490c998a024249e98bb0647377c F src/wherecode.c 85790d7e5365ac41085713331ce52e4343586ad3d37d218ffe00572357baa62b F src/whereexpr.c 1dfda1695e4480c24248157df55bb4d66c732dc8d14ac16b4f076bb15de93d63 @@ -1242,7 +1242,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2 F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28 F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127 -F test/joinH.test 15f501b33d848521964afde9865a92aeca79c8c41fa84dc4dc3f865c9ed8c868 +F test/joinH.test 705157cf9b9b7c207caf960812a7d0e4dc1dd45aa5fb2b563f12df59088645f3 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -2059,8 +2059,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 e6f9c0b1f963033a8e17d13935c5c6b12d263fe10c585035a3d1f1154c6ba5d6 -R 7500f54b9a757a6bdf9e41121051af70 -U larrybr -Z e45f0a7f30148e18d14433c2a4564a3c +P 8f637aae23e6638c064a34262dcf16a3cdfd000fb1fa1b2a834b292fe6659408 +R 162170fabcf6c22e465922e65b3136a8 +U dan +Z 748c21dff95a1a525519cd6fda798ed3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a40e09b2de..b242eaaebc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f637aae23e6638c064a34262dcf16a3cdfd000fb1fa1b2a834b292fe6659408 \ No newline at end of file +1783655ea422185e75593b89e4ef452a6f5496aefd389f88ce7fe4b7d41d6a98 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 8200daca80..bc63c53b58 100644 --- a/src/where.c +++ b/src/where.c @@ -5982,22 +5982,46 @@ WhereInfo *sqlite3WhereBegin( } if( pParse->nErr ) goto whereBeginError; - /* Special case: WHERE terms that do not refer to any tables in the join - ** (constant expressions). Evaluate each such term, and jump over all the - ** generated code if the result is not true. + /* The False-WHERE-Term-Bypass optimization: ** - ** Do not do this if the expression contains non-deterministic functions - ** that are not within a sub-select. This is not strictly required, but - ** preserves SQLite's legacy behaviour in the following two cases: + ** If there are WHERE terms that are false, then no rows will be output, + ** so skip over all of the code generated here. ** - ** FROM ... WHERE random()>0; -- eval random() once per row - ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall + ** Conditions: + ** + ** (1) The WHERE term must not refer to any tables in the join. + ** (2) The term must not come from an ON clause on the + ** right-hand side of a LEFT or FULL JOIN. + ** (3) The term must not come from an ON clause, or there must be + ** no RIGHT or FULL OUTER joins in pTabList. + ** (4) If the expression contains non-deterministic functions + ** that are not within a sub-select. This is not required + ** for correctness but rather to preserves SQLite's legacy + ** behaviour in the following two cases: + ** + ** WHERE random()>0; -- eval random() once per row + ** WHERE (SELECT random())>0; -- eval random() just once overall + ** + ** Note that the Where term need not be a constant in order for this + ** optimization to apply, though it does need to be constant relative to + ** the current subquery (condition 1). The term might include variables + ** from outer queries so that the value of the term changes from one + ** invocation of the current subquery to the next. */ for(ii=0; iinBase; ii++){ - WhereTerm *pT = &sWLB.pWC->a[ii]; + WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */ + Expr *pX; /* The expression of pT */ + int ltoj; /* Left table of the join */ if( pT->wtFlags & TERM_VIRTUAL ) continue; - if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ - sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); + pX = pT->pExpr; + assert( pX!=0 ); + assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) ); + if( pT->prereqAll==0 /* Conditions (1) and (2) */ + && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */ + && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */ + && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 ) + ){ + sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL); pT->wtFlags |= TERM_CODED; } } diff --git a/test/joinH.test b/test/joinH.test index 1d5f66afa2..78d1556293 100644 --- a/test/joinH.test +++ b/test/joinH.test @@ -89,5 +89,35 @@ do_execsql_test 4.4 { SELECT (d IS NULL) FROM t1 RIGHT JOIN t2 ON (j=33); } {1} +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 5.0 { + CREATE TABLE t0(w); + CREATE TABLE t1(x); + CREATE TABLE t2(y); + CREATE TABLE t3(z); + INSERT INTO t3 VALUES('t3val'); +} + +do_execsql_test 5.1 { + SELECT * FROM t1 INNER JOIN t2 ON (0) RIGHT OUTER JOIN t3; +} {{} {} t3val} + +do_execsql_test 5.2 { + SELECT * FROM t1 INNER JOIN t2 ON (0) FULL OUTER JOIN t3; +} {{} {} t3val} + +do_execsql_test 5.3 { + SELECT * FROM t3 LEFT JOIN t2 ON (0); +} {t3val {}} + +do_execsql_test 5.4 { + SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0) RIGHT JOIN t3 +} {{} {} {} t3val} + +do_execsql_test 5.5 { + SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0) +} {} finish_test From 77a159212b59a578fd3e2bb82c4a826616148ad0 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 25 Apr 2023 14:54:18 +0000 Subject: [PATCH 05/16] Remove unused variable ltoj accidentally added by [1783655e]. FossilOrigin-Name: faa1575ce0a39a2335a77057e8769a4e67aedd6326b4627988d03f0cb21fc39a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 39088ebefe..414190236b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\sassuming\sthat\san\sexpression\sin\san\sON()\sclause\sthat\sevaluates\sto\szero\simplies\sthat\sthe\squery\swill\sreturn\szero\srows\swhen\sthe\squery\scontains\sa\sRIGHT\sJOIN.\s[forum:95849acbe1|Forum\sPost\s95849acbe1]. -D 2023-04-25T14:37:12.443 +C Remove\sunused\svariable\sltoj\saccidentally\sadded\sby\s[1783655e]. +D 2023-04-25T14:54:18.391 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -717,7 +717,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 3f4ac276a60bda76f9f1f6f1c2c38599bacd4987e5efcd3f7fed2647bf97280a F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 8899e22a397c839f551c8e1741c100ae2675feb0fe0a383d55816f2ca3d2b583 +F src/where.c f69d94f34e1c523cd9b66041e4afe015cad29888617f3c09a2a5bc36018917d0 F src/whereInt.h e25203e5bfee149f5f1225ae0166cfb4f1e65490c998a024249e98bb0647377c F src/wherecode.c 85790d7e5365ac41085713331ce52e4343586ad3d37d218ffe00572357baa62b F src/whereexpr.c 1dfda1695e4480c24248157df55bb4d66c732dc8d14ac16b4f076bb15de93d63 @@ -2059,8 +2059,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 8f637aae23e6638c064a34262dcf16a3cdfd000fb1fa1b2a834b292fe6659408 -R 162170fabcf6c22e465922e65b3136a8 +P 1783655ea422185e75593b89e4ef452a6f5496aefd389f88ce7fe4b7d41d6a98 +R af6a6a477260f7ae036c05114ac0158b U dan -Z 748c21dff95a1a525519cd6fda798ed3 +Z 782079e9b761f4a6226411428cf5075b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b242eaaebc..07eaee3eb2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1783655ea422185e75593b89e4ef452a6f5496aefd389f88ce7fe4b7d41d6a98 \ No newline at end of file +faa1575ce0a39a2335a77057e8769a4e67aedd6326b4627988d03f0cb21fc39a \ No newline at end of file diff --git a/src/where.c b/src/where.c index bc63c53b58..f517150e12 100644 --- a/src/where.c +++ b/src/where.c @@ -6011,7 +6011,6 @@ WhereInfo *sqlite3WhereBegin( for(ii=0; iinBase; ii++){ WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */ Expr *pX; /* The expression of pT */ - int ltoj; /* Left table of the join */ if( pT->wtFlags & TERM_VIRTUAL ) continue; pX = pT->pExpr; assert( pX!=0 ); From d924af2325777f439d27b2e10629480e65e570c8 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 26 Apr 2023 18:23:47 +0000 Subject: [PATCH 06/16] When changing a large integer into a floating point value, cancel the string representation. Fix for [forum:/forumpost/5c74a3bc4a|forum post 5c74a3bc4a]. FossilOrigin-Name: 3e2da8a7e35c839128d26aac575605e1e34889e8ab3484440bdd65c4d752c6bb --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/vdbe.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index d3df300e36..8a7e6b0ec7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\sthe\ssessions\smodule\sto\sbe\sconfigured\sto\scapture\schanges\sfrom\stables\swith\sno\sexplicit\sPRIMARY\sKEY. -D 2023-04-25T20:41:19.652 +C When\schanging\sa\slarge\sinteger\sinto\sa\sfloating\spoint\svalue,\scancel\sthe\nstring\srepresentation.\s\sFix\sfor\n[forum:/forumpost/5c74a3bc4a|forum\spost\s5c74a3bc4a]. +D 2023-04-26T18:23:47.136 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -703,7 +703,7 @@ F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c b1d8d87c4c8c77e70f48c43f91444fd66d91532693573b70b837afd572010176 F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd -F src/vdbe.c a6c52ba65e8ceb574fe0eda62af84e6c50c176ffc5f310c613425f7ab2b1484b +F src/vdbe.c 1d3e3b10ce83d1470bc349e9fe842ddded303591bae4c49e3292975f3c4d9beb F src/vdbe.h 637ae853b7d42ae3951034cc63ab7c8af837861f79504cdb5399552fcd89a884 F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb F src/vdbeapi.c 1a95162e26d5eda3b7b46fbe4fcbc33eb7f801529d66fc2e14c52094a5523339 @@ -2060,9 +2060,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 faa1575ce0a39a2335a77057e8769a4e67aedd6326b4627988d03f0cb21fc39a 8a612f0860126c0c8473b1e65fcabb9a8821d8bf09fdf3f6018acfc99df9af71 -R ad733d62a9c199f3e70fa032fba3e6af -T +closed 8a612f0860126c0c8473b1e65fcabb9a8821d8bf09fdf3f6018acfc99df9af71 -U dan -Z 8fa09f18d44011739b0f388938c890f1 +P 5d4431bc44e206f48f3bcc1f51399b38bd4cb418e7e50a37495475fb8da04646 +R 890da1742f527a634e898a7eb7549799 +U drh +Z a31dc7374b94808e2db1fdf0feced2a2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 67fdd8c5ed..b14d7af345 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5d4431bc44e206f48f3bcc1f51399b38bd4cb418e7e50a37495475fb8da04646 \ No newline at end of file +3e2da8a7e35c839128d26aac575605e1e34889e8ab3484440bdd65c4d752c6bb \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index ba726a7954..738596daea 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3240,7 +3240,7 @@ case OP_Affinity: { }else{ pIn1->u.r = (double)pIn1->u.i; pIn1->flags |= MEM_Real; - pIn1->flags &= ~MEM_Int; + pIn1->flags &= ~(MEM_Int|MEM_Str); } } REGISTER_TRACE((int)(pIn1-aMem), pIn1); From 6a9ba9a8c2fae4c999fd152fb510537b93345df6 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 26 Apr 2023 18:50:49 +0000 Subject: [PATCH 07/16] Fix a typo in a printf() format string the sessions module. FossilOrigin-Name: 14d1c4a828660bc137dcea1bb4cc439e1ed3872867a0dab486f6a639ef3bcc45 --- ext/session/sqlite3session.c | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index e601a4ae7a..89cffac199 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -1765,7 +1765,7 @@ static char *sessionAllCols( int ii; char *zRet = 0; for(ii=0; iinCol; ii++){ - zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"%s", + zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"", zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii] ); if( !zRet ) break; diff --git a/manifest b/manifest index 8a7e6b0ec7..c941ae48fb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\schanging\sa\slarge\sinteger\sinto\sa\sfloating\spoint\svalue,\scancel\sthe\nstring\srepresentation.\s\sFix\sfor\n[forum:/forumpost/5c74a3bc4a|forum\spost\s5c74a3bc4a]. -D 2023-04-26T18:23:47.136 +C Fix\sa\stypo\sin\sa\sprintf()\sformat\sstring\sthe\ssessions\smodule. +D 2023-04-26T18:50:49.563 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -470,7 +470,7 @@ F ext/session/sessionrowid.test 6323ba831721205fd729929745038fd54e9d128c66c654b8 F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795 F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc -F ext/session/sqlite3session.c a0d7d71f9b111e443b53afc49b6cb5ccf48734af216c91dbe6640b7e4cd8c740 +F ext/session/sqlite3session.c c30768077832f04f6ae98ab5a5347eae78b4f840bc958e16ae8aa970261a315e F ext/session/sqlite3session.h 24299a3b64f11afc4422ce92d030ffdb2d3181851a1763b4a0432e195b2a8a16 F ext/session/test_session.c 5285482f83cd92b4c1fe12fcf88210566a18312f4f2aa110f6399dae46aeccbb F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 @@ -2060,8 +2060,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 5d4431bc44e206f48f3bcc1f51399b38bd4cb418e7e50a37495475fb8da04646 -R 890da1742f527a634e898a7eb7549799 -U drh -Z a31dc7374b94808e2db1fdf0feced2a2 +P 3e2da8a7e35c839128d26aac575605e1e34889e8ab3484440bdd65c4d752c6bb +R 4e23a1ec1e088b34c19a8052565eac29 +U dan +Z 09bae246348989754f2af6790026c07b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b14d7af345..6ee1d6b0d8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e2da8a7e35c839128d26aac575605e1e34889e8ab3484440bdd65c4d752c6bb \ No newline at end of file +14d1c4a828660bc137dcea1bb4cc439e1ed3872867a0dab486f6a639ef3bcc45 \ No newline at end of file From 2e225a35b4242c36626a88973ee31704992b234e Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 27 Apr 2023 13:55:29 +0000 Subject: [PATCH 08/16] Fix a problem on windows sometimes causing SQLITE_NOMEM to be returned if an error occurred while opening a temp file. FossilOrigin-Name: c22a39a6b28e3039fe453c0c0db98744b8a63ef9063cc3f6e0ed67d2506d34be --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_win.c | 11 ++++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index c941ae48fb..38d2562688 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sa\sprintf()\sformat\sstring\sthe\ssessions\smodule. -D 2023-04-26T18:50:49.563 +C Fix\sa\sproblem\son\swindows\ssometimes\scausing\sSQLITE_NOMEM\sto\sbe\sreturned\sif\san\serror\soccurred\swhile\sopening\sa\stemp\sfile. +D 2023-04-27T13:55:29.757 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -618,7 +618,7 @@ F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107 F src/os_unix.c 1b3ddb7814c4bf37f494c04d2ab30c1ced5b2c927267e1930ce7cd388787a96d -F src/os_win.c 295fe45f18bd86f2477f4cd79f3377c6f883ceb941b1f46808665c73747f2345 +F src/os_win.c 20c2f020b54fe6ae210c1f200efc097ac50e7e7b24f64c632c1b751ac1f96899 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 9d36ddedc842e993c88c222ed914822dbd6f8ece3c648fde04468637012a034a F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3 @@ -2060,8 +2060,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 3e2da8a7e35c839128d26aac575605e1e34889e8ab3484440bdd65c4d752c6bb -R 4e23a1ec1e088b34c19a8052565eac29 +P 14d1c4a828660bc137dcea1bb4cc439e1ed3872867a0dab486f6a639ef3bcc45 +R 1e3870610983faacb84c1d55e8f701dd U dan -Z 09bae246348989754f2af6790026c07b +Z ef68dfd966e00e89b716183914f3d8f9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6ee1d6b0d8..ff4ed9d11e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -14d1c4a828660bc137dcea1bb4cc439e1ed3872867a0dab486f6a639ef3bcc45 \ No newline at end of file +c22a39a6b28e3039fe453c0c0db98744b8a63ef9063cc3f6e0ed67d2506d34be \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index abecf1b936..33275113ad 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -5197,7 +5197,7 @@ static int winOpen( if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } @@ -5214,7 +5214,7 @@ static int winOpen( if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } @@ -5234,7 +5234,7 @@ static int winOpen( if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } @@ -5453,6 +5453,11 @@ static int winAccess( void *zConverted; UNUSED_PARAMETER(pVfs); + if( zFilename==0 ){ + *pResOut = 0; + return SQLITE_OK; + } + SimulateIOError( return SQLITE_IOERR_ACCESS; ); OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", zFilename, flags, pResOut)); From cf5dce045f5d34df466993b40d1a9feae0915abb Mon Sep 17 00:00:00 2001 From: mistachkin Date: Thu, 27 Apr 2023 21:31:21 +0000 Subject: [PATCH 09/16] Adjust OSTRACE usage so that it works with the changes in the previous check-in. FossilOrigin-Name: 1eb4573e9092d350d00d05ba716cb0272e2dbb1ecbaadc2a7cc22de0b8cc2bda --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os_win.c | 12 +++++++----- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 38d2562688..eb73222d1b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\son\swindows\ssometimes\scausing\sSQLITE_NOMEM\sto\sbe\sreturned\sif\san\serror\soccurred\swhile\sopening\sa\stemp\sfile. -D 2023-04-27T13:55:29.757 +C Adjust\sOSTRACE\susage\sso\sthat\sit\sworks\swith\sthe\schanges\sin\sthe\sprevious\scheck-in. +D 2023-04-27T21:31:21.305 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -618,7 +618,7 @@ F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107 F src/os_unix.c 1b3ddb7814c4bf37f494c04d2ab30c1ced5b2c927267e1930ce7cd388787a96d -F src/os_win.c 20c2f020b54fe6ae210c1f200efc097ac50e7e7b24f64c632c1b751ac1f96899 +F src/os_win.c 2b2411279f7b24f927591561303fc5871845732df42641cbf695c23640b16975 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 9d36ddedc842e993c88c222ed914822dbd6f8ece3c648fde04468637012a034a F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3 @@ -2060,8 +2060,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 14d1c4a828660bc137dcea1bb4cc439e1ed3872867a0dab486f6a639ef3bcc45 -R 1e3870610983faacb84c1d55e8f701dd -U dan -Z ef68dfd966e00e89b716183914f3d8f9 +P c22a39a6b28e3039fe453c0c0db98744b8a63ef9063cc3f6e0ed67d2506d34be +R cc0091be8db1b63c66828854cc8ff562 +U mistachkin +Z ac07319bd47da651541c0acc4d52b4bc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ff4ed9d11e..d3c1b0063d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c22a39a6b28e3039fe453c0c0db98744b8a63ef9063cc3f6e0ed67d2506d34be \ No newline at end of file +1eb4573e9092d350d00d05ba716cb0272e2dbb1ecbaadc2a7cc22de0b8cc2bda \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index 33275113ad..b7b6897452 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -5453,15 +5453,17 @@ static int winAccess( void *zConverted; UNUSED_PARAMETER(pVfs); - if( zFilename==0 ){ - *pResOut = 0; - return SQLITE_OK; - } - SimulateIOError( return SQLITE_IOERR_ACCESS; ); OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", zFilename, flags, pResOut)); + if( zFilename==0 ){ + *pResOut = 0; + OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", + zFilename, pResOut, *pResOut)); + return SQLITE_OK; + } + zConverted = winConvertFromUtf8Filename(zFilename); if( zConverted==0 ){ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); From 263b86c54c9379a7a667956d15953bd1f255ff09 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Thu, 27 Apr 2023 22:17:12 +0000 Subject: [PATCH 10/16] Fix compilation issues seen with older versions of MSVC. FossilOrigin-Name: 4ba2a651120391d779a3db9881c0fb17e1322cc9d8738f915a46e31a2f313578 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/msvc.h | 4 ++++ src/shell.c.in | 6 +++++- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index eb73222d1b..1307580539 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adjust\sOSTRACE\susage\sso\sthat\sit\sworks\swith\sthe\schanges\sin\sthe\sprevious\scheck-in. -D 2023-04-27T21:31:21.305 +C Fix\scompilation\sissues\sseen\swith\solder\sversions\sof\sMSVC. +D 2023-04-27T22:17:12.102 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -605,7 +605,7 @@ F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6 F src/mem5.c b7da5c10a726aacacc9ad7cdcb0667deec643e117591cc69cf9b4b9e7f3e96ff F src/memdb.c 559c42e61eb70cd6d4bc692b042497133c6d96c09a3d514d92f3dac72268e223 F src/memjournal.c c283c6c95d940eb9dc70f1863eef3ee40382dbd35e5a1108026e7817c206e8a0 -F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8 +F src/msvc.h 80b35f95d93bf996ccb3e498535255f2ef1118c78764719a7cd15ab4106ccac9 F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25 F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 @@ -634,7 +634,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c f879cef11c462a2c37a8c906932781e384c3bb32042c355a704a043029c90d27 -F src/shell.c.in e4762c17316110d4b65afac3572a4d134539a4178ac2afe4821de23f509a728f +F src/shell.c.in 5dcbcbcd8d984d05737172bcc23678ec34367905871ca1fdec4ca831bfd806fa F src/sqlite.h.in 4fff9c6cc5d4cbba9532a668112efb6dc469c425e1a2196664d7c07d508363ef F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4 @@ -2060,8 +2060,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 c22a39a6b28e3039fe453c0c0db98744b8a63ef9063cc3f6e0ed67d2506d34be -R cc0091be8db1b63c66828854cc8ff562 +P 1eb4573e9092d350d00d05ba716cb0272e2dbb1ecbaadc2a7cc22de0b8cc2bda +R 1210fb0fa6a88a694d8f60efc7074476 U mistachkin -Z ac07319bd47da651541c0acc4d52b4bc +Z e10e84fb88698cc9750bcbdb28b62bd0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d3c1b0063d..fc0f04b096 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1eb4573e9092d350d00d05ba716cb0272e2dbb1ecbaadc2a7cc22de0b8cc2bda \ No newline at end of file +4ba2a651120391d779a3db9881c0fb17e1322cc9d8738f915a46e31a2f313578 \ No newline at end of file diff --git a/src/msvc.h b/src/msvc.h index f174227330..10675e9a71 100644 --- a/src/msvc.h +++ b/src/msvc.h @@ -38,4 +38,8 @@ #define SQLITE_4_BYTE_ALIGNED_MALLOC #endif /* defined(_MSC_VER) && !defined(_WIN64) */ +#if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 +#define HAVE_LOG2 0 +#endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */ + #endif /* SQLITE_MSVC_H */ diff --git a/src/shell.c.in b/src/shell.c.in index 5a7a7e0091..a6d67f4095 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -3565,10 +3565,14 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){ sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC); if( rc==SQLITE_OK && pQ && sqlite3_step(pQ)==SQLITE_ROW ){ sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0)); +#ifdef NAN }else if( sqlite3_strlike("_NAN", zVar, 0)==0 ){ sqlite3_bind_double(pStmt, i, NAN); +#endif +#ifdef INFINITY }else if( sqlite3_strlike("_INF", zVar, 0)==0 ){ sqlite3_bind_double(pStmt, i, INFINITY); +#endif }else{ sqlite3_bind_null(pStmt, i); } @@ -4995,10 +4999,10 @@ static int showHelp(FILE *out, const char *zPattern){ ** Otherwise => whole help for documented commands */ enum HelpWanted hw = HW_SummaryOnly; + enum HelpHave hh = HH_More; if( zPattern!=0 ){ hw = (*zPattern=='0')? HW_NoCull|HW_Undoc : HW_NoCull; } - enum HelpHave hh = HH_More; for(i=0; i Date: Thu, 27 Apr 2023 23:40:03 +0000 Subject: [PATCH 11/16] Remove an ALWAYS() macro that can in fact sometimes be false. [forum:/forumpost/f0e872fcee|Forum post f0e872fcee]. FossilOrigin-Name: d85880e4ed89e2198beea642818051f7a91a71fea9929be0a7ed0603b493ce47 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbe.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 1307580539..546858402e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scompilation\sissues\sseen\swith\solder\sversions\sof\sMSVC. -D 2023-04-27T22:17:12.102 +C Remove\san\sALWAYS()\smacro\sthat\scan\sin\sfact\ssometimes\sbe\sfalse.\n[forum:/forumpost/f0e872fcee|Forum\spost\sf0e872fcee]. +D 2023-04-27T23:40:03.444 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -703,7 +703,7 @@ F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c b1d8d87c4c8c77e70f48c43f91444fd66d91532693573b70b837afd572010176 F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd -F src/vdbe.c 1d3e3b10ce83d1470bc349e9fe842ddded303591bae4c49e3292975f3c4d9beb +F src/vdbe.c 94d5520d2a287216c47e6fb641ee88ffd934b0d40c235d693d38bcd0e0750357 F src/vdbe.h 637ae853b7d42ae3951034cc63ab7c8af837861f79504cdb5399552fcd89a884 F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb F src/vdbeapi.c 1a95162e26d5eda3b7b46fbe4fcbc33eb7f801529d66fc2e14c52094a5523339 @@ -2060,8 +2060,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 1eb4573e9092d350d00d05ba716cb0272e2dbb1ecbaadc2a7cc22de0b8cc2bda -R 1210fb0fa6a88a694d8f60efc7074476 -U mistachkin -Z e10e84fb88698cc9750bcbdb28b62bd0 +P 4ba2a651120391d779a3db9881c0fb17e1322cc9d8738f915a46e31a2f313578 +R 17f49f4919f4d8f5c0f5d76a60091614 +U drh +Z 328809aebe8b52d41e5cb3bc142e5a4c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fc0f04b096..a9c8c64d27 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4ba2a651120391d779a3db9881c0fb17e1322cc9d8738f915a46e31a2f313578 \ No newline at end of file +d85880e4ed89e2198beea642818051f7a91a71fea9929be0a7ed0603b493ce47 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 738596daea..ea2e6fc5b1 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2745,7 +2745,7 @@ case OP_IfNullRow: { /* jump */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; - if( ALWAYS(pC) && pC->nullRow ){ + if( pC && pC->nullRow ){ sqlite3VdbeMemSetNull(aMem + pOp->p3); goto jump_to_p2; } From bfd28f9e01ae9a8436095a033ce96cf16b9c6f5b Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 27 Apr 2023 23:44:38 +0000 Subject: [PATCH 12/16] Remove a faulty assert() from the CLI. [forum:/forumpost/726c4f7db0|Forum post 726c4f7db0]. FossilOrigin-Name: 4bbebb6bfb9910265d91b777c1711b3b8e0732bcf299f7459b20c4ea110422bd --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 546858402e..bbffdf19e1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sALWAYS()\smacro\sthat\scan\sin\sfact\ssometimes\sbe\sfalse.\n[forum:/forumpost/f0e872fcee|Forum\spost\sf0e872fcee]. -D 2023-04-27T23:40:03.444 +C Remove\sa\sfaulty\sassert()\sfrom\sthe\sCLI.\n[forum:/forumpost/726c4f7db0|Forum\spost\s726c4f7db0]. +D 2023-04-27T23:44:38.716 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -634,7 +634,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c f879cef11c462a2c37a8c906932781e384c3bb32042c355a704a043029c90d27 -F src/shell.c.in 5dcbcbcd8d984d05737172bcc23678ec34367905871ca1fdec4ca831bfd806fa +F src/shell.c.in 3b5633b7c78e51df21af693ce27cccca28e6118480060876d6be968c2f7a577c F src/sqlite.h.in 4fff9c6cc5d4cbba9532a668112efb6dc469c425e1a2196664d7c07d508363ef F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4 @@ -2060,8 +2060,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 4ba2a651120391d779a3db9881c0fb17e1322cc9d8738f915a46e31a2f313578 -R 17f49f4919f4d8f5c0f5d76a60091614 +P d85880e4ed89e2198beea642818051f7a91a71fea9929be0a7ed0603b493ce47 +R c57990c4154d9f0a3a4f65c13761b58d U drh -Z 328809aebe8b52d41e5cb3bc142e5a4c +Z d40988ca57efd61e3977061d11afa616 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a9c8c64d27..accb12491c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d85880e4ed89e2198beea642818051f7a91a71fea9929be0a7ed0603b493ce47 \ No newline at end of file +4bbebb6bfb9910265d91b777c1711b3b8e0732bcf299f7459b20c4ea110422bd \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index a6d67f4095..d7621c0c9e 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -10516,7 +10516,8 @@ static int do_meta_command(char *zLine, ShellState *p){ if( bDebug ) utf8_printf(p->out, "%s\n", zRevText); lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0); if( lrc!=SQLITE_OK ){ - assert(lrc==SQLITE_NOMEM); + /* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the + ** user does cruel and unnatural things like ".limit expr_depth 0". */ rc = 1; }else{ if( zLike ) sqlite3_bind_text(pStmt,1,zLike,-1,SQLITE_STATIC); From 93b4c3beb8f005e1c0ce6f27b1675e4b2f24acc4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 27 Apr 2023 23:59:51 +0000 Subject: [PATCH 13/16] Use a new technique to detect fresh OOM faults in columnName() that does not rely on there being no OOMs prior to entry into columnName(), as [forum/forumpost/fb6811c2f9|forum post fb6811c2f9] demonstrates a technique which could cause an OOM prior to entry into columnName(). FossilOrigin-Name: a63346d6a0c0ca7ba4c87499de2e461be9c77e9b5d98f2bebf308cdb6599f33c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeapi.c | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index bbffdf19e1..cbe41d4e9d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sa\sfaulty\sassert()\sfrom\sthe\sCLI.\n[forum:/forumpost/726c4f7db0|Forum\spost\s726c4f7db0]. -D 2023-04-27T23:44:38.716 +C Use\sa\snew\stechnique\sto\sdetect\sfresh\sOOM\sfaults\sin\scolumnName()\sthat\sdoes\snot\nrely\son\sthere\sbeing\sno\sOOMs\sprior\sto\sentry\sinto\scolumnName(),\sas\n[forum/forumpost/fb6811c2f9|forum\spost\sfb6811c2f9]\sdemonstrates\sa\stechnique\nwhich\scould\scause\san\sOOM\sprior\sto\sentry\sinto\scolumnName(). +D 2023-04-27T23:59:51.813 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -706,7 +706,7 @@ F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd F src/vdbe.c 94d5520d2a287216c47e6fb641ee88ffd934b0d40c235d693d38bcd0e0750357 F src/vdbe.h 637ae853b7d42ae3951034cc63ab7c8af837861f79504cdb5399552fcd89a884 F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb -F src/vdbeapi.c 1a95162e26d5eda3b7b46fbe4fcbc33eb7f801529d66fc2e14c52094a5523339 +F src/vdbeapi.c b4982cde547054c4f7341198db3c3008a48e1eb028f757601bf5bf2fc026cbcf F src/vdbeaux.c 6ee48db408d4c297a363f1e31145c09793a580e7c508bb36063dd017d67117a2 F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd F src/vdbemem.c 1d9a0f37b0097fbb53f0d7ba081f7181b83cee2c6f46364706ea0c3896bd8ec0 @@ -2060,8 +2060,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 d85880e4ed89e2198beea642818051f7a91a71fea9929be0a7ed0603b493ce47 -R c57990c4154d9f0a3a4f65c13761b58d +P 4bbebb6bfb9910265d91b777c1711b3b8e0732bcf299f7459b20c4ea110422bd +R 59c8d7a772734f630b5bf6fd205de302 U drh -Z d40988ca57efd61e3977061d11afa616 +Z d29ba302c14b4aed5db886f9a3fc4bd5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index accb12491c..b9ba76d6e8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4bbebb6bfb9910265d91b777c1711b3b8e0732bcf299f7459b20c4ea110422bd \ No newline at end of file +a63346d6a0c0ca7ba4c87499de2e461be9c77e9b5d98f2bebf308cdb6599f33c \ No newline at end of file diff --git a/src/vdbeapi.c b/src/vdbeapi.c index d1e1232b1a..d8fcda96df 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1337,9 +1337,9 @@ static const void *columnName( assert( db!=0 ); n = sqlite3_column_count(pStmt); if( N=0 ){ + u8 prior_mallocFailed = db->mallocFailed; N += useType*n; sqlite3_mutex_enter(db->mutex); - assert( db->mallocFailed==0 ); #ifndef SQLITE_OMIT_UTF16 if( useUtf16 ){ ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); @@ -1351,7 +1351,8 @@ static const void *columnName( /* A malloc may have failed inside of the _text() call. If this ** is the case, clear the mallocFailed flag and return NULL. */ - if( db->mallocFailed ){ + assert( db->mallocFailed==0 || db->mallocFailed==1 ); + if( db->mallocFailed > prior_mallocFailed ){ sqlite3OomClear(db); ret = 0; } From fe03773305fa7c52e26df3a5794475037fbf456a Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 28 Apr 2023 00:19:55 +0000 Subject: [PATCH 14/16] In the CLI, early out from the output_quoted_string() routine if the input string is NULL. [forum:/forumpost/8a22c0bfa7|forum post 8a22c0bfa7]. FossilOrigin-Name: 2881978d7b7014738a21c590b0430c4fa40e6b00b9547d0284b7656124523ae9 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index cbe41d4e9d..8dfeca3498 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sa\snew\stechnique\sto\sdetect\sfresh\sOOM\sfaults\sin\scolumnName()\sthat\sdoes\snot\nrely\son\sthere\sbeing\sno\sOOMs\sprior\sto\sentry\sinto\scolumnName(),\sas\n[forum/forumpost/fb6811c2f9|forum\spost\sfb6811c2f9]\sdemonstrates\sa\stechnique\nwhich\scould\scause\san\sOOM\sprior\sto\sentry\sinto\scolumnName(). -D 2023-04-27T23:59:51.813 +C In\sthe\sCLI,\searly\sout\sfrom\sthe\soutput_quoted_string()\sroutine\sif\sthe\ninput\sstring\sis\sNULL.\s\s[forum:/forumpost/8a22c0bfa7|forum\spost\s8a22c0bfa7]. +D 2023-04-28T00:19:55.495 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -634,7 +634,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c f879cef11c462a2c37a8c906932781e384c3bb32042c355a704a043029c90d27 -F src/shell.c.in 3b5633b7c78e51df21af693ce27cccca28e6118480060876d6be968c2f7a577c +F src/shell.c.in dbd5bfe1c773115f4e526103807dc3c1484283cd8afe9cf759d64a338408f19f F src/sqlite.h.in 4fff9c6cc5d4cbba9532a668112efb6dc469c425e1a2196664d7c07d508363ef F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4 @@ -2060,8 +2060,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 4bbebb6bfb9910265d91b777c1711b3b8e0732bcf299f7459b20c4ea110422bd -R 59c8d7a772734f630b5bf6fd205de302 +P a63346d6a0c0ca7ba4c87499de2e461be9c77e9b5d98f2bebf308cdb6599f33c +R e1382566976c275dfea2ac91ab17df60 U drh -Z d29ba302c14b4aed5db886f9a3fc4bd5 +Z 06ecc62941bb9eb7ee780cf940024968 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b9ba76d6e8..250b4f032f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a63346d6a0c0ca7ba4c87499de2e461be9c77e9b5d98f2bebf308cdb6599f33c \ No newline at end of file +2881978d7b7014738a21c590b0430c4fa40e6b00b9547d0284b7656124523ae9 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index d7621c0c9e..18690214b5 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1860,6 +1860,7 @@ static void output_quoted_string(FILE *out, const char *z){ int i; char c; setBinaryMode(out, 1); + if( z==0 ) return; for(i=0; (c = z[i])!=0 && c!='\''; i++){} if( c==0 ){ utf8_printf(out,"'%s'",z); From fb016bf25733207d0875302bac7cfb27c7e901b9 Mon Sep 17 00:00:00 2001 From: larrybr Date: Fri, 28 Apr 2023 00:28:06 +0000 Subject: [PATCH 15/16] Make CLI .load slightly harder to abuse. FossilOrigin-Name: 2779f9270cc431786d0e16ef05ec05b0f22dda2307f3bf17467ad0b25304e160 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c.in | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 8dfeca3498..27e6d37f50 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sCLI,\searly\sout\sfrom\sthe\soutput_quoted_string()\sroutine\sif\sthe\ninput\sstring\sis\sNULL.\s\s[forum:/forumpost/8a22c0bfa7|forum\spost\s8a22c0bfa7]. -D 2023-04-28T00:19:55.495 +C Make\sCLI\s.load\sslightly\sharder\sto\sabuse. +D 2023-04-28T00:28:06.476 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -634,7 +634,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c f879cef11c462a2c37a8c906932781e384c3bb32042c355a704a043029c90d27 -F src/shell.c.in dbd5bfe1c773115f4e526103807dc3c1484283cd8afe9cf759d64a338408f19f +F src/shell.c.in 09097e1b9df1f8092e85bf89979e12ca7b608d7efc84551b5d0c8de4dded7797 F src/sqlite.h.in 4fff9c6cc5d4cbba9532a668112efb6dc469c425e1a2196664d7c07d508363ef F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4 @@ -2060,8 +2060,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 a63346d6a0c0ca7ba4c87499de2e461be9c77e9b5d98f2bebf308cdb6599f33c -R e1382566976c275dfea2ac91ab17df60 -U drh -Z 06ecc62941bb9eb7ee780cf940024968 +P 2881978d7b7014738a21c590b0430c4fa40e6b00b9547d0284b7656124523ae9 +R f31a79597744826157054a8d8987cbe4 +U larrybr +Z 94682afadd89800c43fc7c92687bd9b6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 250b4f032f..df2a5b5785 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2881978d7b7014738a21c590b0430c4fa40e6b00b9547d0284b7656124523ae9 \ No newline at end of file +2779f9270cc431786d0e16ef05ec05b0f22dda2307f3bf17467ad0b25304e160 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 18690214b5..7285067bef 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -9192,7 +9192,8 @@ static int do_meta_command(char *zLine, ShellState *p){ const char *zFile, *zProc; char *zErrMsg = 0; failIfSafeMode(p, "cannot run .load in safe mode"); - if( nArg<2 ){ + if( nArg<2 || azArg[1][0]==0 ){ + /* Must have a non-empty FILE. (Will not load self.) */ raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); rc = 1; goto meta_command_exit; From 90f549a0cfb94c25e2126e27ce358618e11e8bd6 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 28 Apr 2023 10:10:52 +0000 Subject: [PATCH 16/16] Do not assert() a bad string representation in an sqlite3_value after an OOM. dbsqlfuzz c822a17a23c524a0ac7cfb203c7198209da15de8. FossilOrigin-Name: 91fee79a01971259b21478e60a069a711a00efc79ddfececa6224a152cd8d09a --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbemem.c | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 27e6d37f50..9f1cd11163 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sCLI\s.load\sslightly\sharder\sto\sabuse. -D 2023-04-28T00:28:06.476 +C Do\snot\sassert()\sa\sbad\sstring\srepresentation\sin\san\ssqlite3_value\safter\nan\sOOM.\s\sdbsqlfuzz\sc822a17a23c524a0ac7cfb203c7198209da15de8. +D 2023-04-28T10:10:52.120 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -709,7 +709,7 @@ F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb F src/vdbeapi.c b4982cde547054c4f7341198db3c3008a48e1eb028f757601bf5bf2fc026cbcf F src/vdbeaux.c 6ee48db408d4c297a363f1e31145c09793a580e7c508bb36063dd017d67117a2 F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd -F src/vdbemem.c 1d9a0f37b0097fbb53f0d7ba081f7181b83cee2c6f46364706ea0c3896bd8ec0 +F src/vdbemem.c 1cac4028c0dabbf1f3259f107440e2780e05ac9fe419e9709e6eb4e166ba714b F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35 F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823 F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac @@ -2060,8 +2060,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 2881978d7b7014738a21c590b0430c4fa40e6b00b9547d0284b7656124523ae9 -R f31a79597744826157054a8d8987cbe4 -U larrybr -Z 94682afadd89800c43fc7c92687bd9b6 +P 2779f9270cc431786d0e16ef05ec05b0f22dda2307f3bf17467ad0b25304e160 +R fcf6991862458e9816409ec8d717ddc8 +U drh +Z d3df2b888a0fbd6bd36c6662515c45b3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index df2a5b5785..e2c06ba976 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2779f9270cc431786d0e16ef05ec05b0f22dda2307f3bf17467ad0b25304e160 \ No newline at end of file +91fee79a01971259b21478e60a069a711a00efc79ddfececa6224a152cd8d09a \ No newline at end of file diff --git a/src/vdbemem.c b/src/vdbemem.c index 7b3b970f3f..d3cd55ba9f 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -157,6 +157,7 @@ int sqlite3VdbeMemValidStrRep(Mem *p){ char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; + if( p->db && p->db->mallocFailed ) return 1; if( p->flags & MEM_Term ){ /* Insure that the string is properly zero-terminated. Pay particular ** attention to the case where p->n is odd */