From 6dc29e60c813032d8bbdd98a14f42e1c9c5ed018 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 2 Jun 2015 09:19:22 +0000 Subject: [PATCH] Modify the sessions module to ignore all operations on tables with no primary keys as documented. FossilOrigin-Name: bdaf9575cd9ebb33dc5da4062a84bca79e7b0fec --- ext/session/session1.test | 51 ++++++++++++--- ext/session/sessionE.test | 116 +++++++++++++++++++++++++++++++++ ext/session/session_common.tcl | 10 +++ ext/session/sqlite3session.c | 51 ++++++++------- manifest | 19 +++--- manifest.uuid | 2 +- 6 files changed, 207 insertions(+), 42 deletions(-) create mode 100644 ext/session/sessionE.test diff --git a/ext/session/session1.test b/ext/session/session1.test index 1c853a97a1..fc74a1e84e 100644 --- a/ext/session/session1.test +++ b/ext/session/session1.test @@ -20,16 +20,6 @@ ifcapable !session {finish_test; return} set testprefix session1 -proc do_changeset_test {tn session res} { - set r [list] - foreach x $res {lappend r $x} - uplevel do_test $tn [list [subst -nocommands { - set x [list] - sqlite3session_foreach c [$session changeset] { lappend x [set c] } - set x - }]] [list $r] -} - proc do_changeset_invert_test {tn session res} { set r [list] foreach x $res {lappend r $x} @@ -525,6 +515,47 @@ do_changeset_test 9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} S delete catch { db2 close } +#------------------------------------------------------------------------- +# Test a really long table name. +# +reset_db +set tblname [string repeat tblname123 100] +do_test 10.1.1 { + execsql " + CREATE TABLE $tblname (a PRIMARY KEY, b); + INSERT INTO $tblname VALUES('xyz', 'def'); + " + sqlite3session S db main + S attach $tblname + execsql " + INSERT INTO $tblname VALUES('uvw', 'abc'); + DELETE FROM $tblname WHERE a = 'xyz'; + " +} {} +breakpoint +do_changeset_test 10.1.2 S " + {INSERT $tblname 0 X. {} {t uvw t abc}} + {DELETE $tblname 0 X. {t xyz t def} {}} +" +do_test 10.1.4 { S delete } {} + +#--------------------------------------------------------------- +reset_db +do_execsql_test 11.1 { + CREATE TABLE t1(a, b); +} +do_test 11.2 { + sqlite3session S db main + S attach t1 + execsql { + INSERT INTO t1 VALUES(1, 2); + } + S changeset +} {} + +S delete + + #------------------------------------------------------------------------- # Test a really long table name. # diff --git a/ext/session/sessionE.test b/ext/session/sessionE.test new file mode 100644 index 0000000000..57962eb6ba --- /dev/null +++ b/ext/session/sessionE.test @@ -0,0 +1,116 @@ +# 2015 June 02 +# +# 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. +# +#*********************************************************************** +# +# This file implements regression tests for the sessions module. +# Specifically, it tests that operations on tables without primary keys +# are ignored. +# + + + +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 sessionE + +# +# Test plan: +# +# 1.*: Test that non-PK tables are not auto-attached. +# 2.*: Test that explicitly attaching a non-PK table is a no-op. +# 3.*: Test that sqlite3session_diff() on a non-PK table is a no-op. +# + + +#-------------------------------------------------------------------------- +reset_db +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a PRIMARY KEY, b); +} +do_test 1.1 { + sqlite3session S db main + S attach * + breakpoint + execsql { + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t2 VALUES(1, 2); + } +} {} +do_changeset_test 1.2 S { + {INSERT t2 0 X. {} {i 1 i 2}} +} +S delete + +reset_db +do_execsql_test 2.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a PRIMARY KEY, b); +} +do_test 2.1 { + sqlite3session S db main + S attach t1 + S attach t2 + breakpoint + execsql { + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t2 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + INSERT INTO t2 VALUES(5, 6); + } +} {} +do_changeset_test 2.2 S { + {INSERT t2 0 X. {} {i 3 i 4}} + {INSERT t2 0 X. {} {i 5 i 6}} +} +S delete + +reset_db +forcedelete test.db2 +do_execsql_test 3.0 { + ATTACH 'test.db2' AS aux; + CREATE TABLE aux.t1(a, b); + CREATE TABLE aux.t2(a PRIMARY KEY, b); + + CREATE TABLE t1(a, b); + CREATE TABLE t2(a PRIMARY KEY, b); + + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t2 VALUES(3, 4); +} +do_test 3.1 { + sqlite3session S db main + S attach t1 + S diff aux t1 + + S attach t2 + S diff aux t2 +} {} +do_changeset_test 3.2 S { + {INSERT t2 0 X. {} {i 3 i 4}} +} +do_execsql_test 3.3 { + INSERT INTO t1 VALUES(5, 6); + INSERT INTO t2 VALUES(7, 8); +} +do_changeset_test 3.4 S { + {INSERT t2 0 X. {} {i 3 i 4}} + {INSERT t2 0 X. {} {i 7 i 8}} +} + + +S delete + + + diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl index d6ce27a850..f27ad11dc0 100644 --- a/ext/session/session_common.tcl +++ b/ext/session/session_common.tcl @@ -1,4 +1,14 @@ +proc do_changeset_test {tn session res} { + set r [list] + foreach x $res {lappend r $x} + uplevel do_test $tn [list [subst -nocommands { + set x [list] + sqlite3session_foreach c [$session changeset] { lappend x [set c] } + set x + }]] [list $r] +} + proc do_conflict_test {tn args} { proc xConflict {args} { diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 287c5929c1..39923ee779 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -1008,32 +1008,33 @@ static int sessionTableInfo( /* ** This function is only called from within a pre-update handler for a ** write to table pTab, part of session pSession. If this is the first -** write to this table, set the SessionTable.nCol variable to the number -** of columns in the table. +** write to this table, initalize the SessionTable.nCol, azCol[] and +** abPK[] arrays accordingly. ** -** Otherwise, if this is not the first time this table has been written -** to, check that the number of columns in the table has not changed. If -** it has not, return zero. -** -** If the number of columns in the table has changed since the last write -** was recorded, set the session error-code to SQLITE_SCHEMA and return -** non-zero. Users are not allowed to change the number of columns in a table -** for which changes are being recorded by the session module. If they do so, -** it is an error. +** If an error occurs, an error code is stored in sqlite3_session.rc and +** non-zero returned. Or, if no error occurs but the table has no primary +** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to +** indicate that updates on this table should be ignored. SessionTable.abPK +** is set to NULL in this case. */ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ if( pTab->nCol==0 ){ + u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->abPK + pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK ); + if( pSession->rc==SQLITE_OK ){ + int i; + for(i=0; inCol; i++){ + if( abPK[i] ){ + pTab->abPK = abPK; + break; + } + } + } } - if( pSession->rc==SQLITE_OK - && pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) - ){ - pSession->rc = SQLITE_SCHEMA; - } - return pSession->rc; + return (pSession->rc || pTab->abPK==0); } /* @@ -1058,6 +1059,13 @@ static void sessionPreupdateOneChange( /* Load table details if required */ if( sessionInitTable(pSession, pTab) ) return; + /* 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) ){ + pSession->rc = SQLITE_SCHEMA; + return; + } + /* Grow the hash table if required */ if( sessionGrowHash(0, pTab) ){ pSession->rc = SQLITE_NOMEM; @@ -1465,10 +1473,9 @@ int sqlite3session_diff( /* Locate and if necessary initialize the target table object */ rc = sessionFindTable(pSession, zTbl, &pTo); if( pTo==0 ) goto diff_out; - if( pTo->nCol==0 ){ - rc = pSession->rc = sessionTableInfo(db, zDb, - pTo->zName, &pTo->nCol, 0, &pTo->azCol, &pTo->abPK - ); + if( sessionInitTable(pSession, pTo) ){ + rc = pSession->rc; + goto diff_out; } /* Check the table schemas match */ diff --git a/manifest b/manifest index 25dfe229ee..434493b0a8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Import\srecent\senhancements\sfrom\strunk. -D 2015-05-29T19:04:58.908 +C Modify\sthe\ssessions\smodule\sto\signore\sall\soperations\son\stables\swith\sno\sprimary\skeys\sas\sdocumented. +D 2015-06-02T09:19:22.231 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 58c16cc8cd876ed112902e70cf33d33f3270b5aa F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -166,7 +166,7 @@ F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a -F ext/session/session1.test 4653867f32a98ce4bbb4a181aac6debe51ca4dfb +F ext/session/session1.test d4f53b9b5add7eeb358e535d6e18552142092429 F ext/session/session2.test a95a2d270b32638c1acba7cb9c81856712d469ac F ext/session/session3.test a7a9ce59b8d1e49e2cc23d81421ac485be0eea01 F ext/session/session4.test a6ed685da7a5293c5d6f99855bcf41dbc352ca84 @@ -178,9 +178,10 @@ F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f F ext/session/sessionB.test 06961b7c3641151f5d23088250ecad132501113c F ext/session/sessionC.test 3982f8577b0744c5ce3aaef7cfeb5bd903f17fe4 F ext/session/sessionD.test d4744c78334162851d2a2f285c7e603e31b49aa2 -F ext/session/session_common.tcl 9de0451b6a47218fc16b9ed8876b6238a0a3d88d +F ext/session/sessionE.test 9ebeae9918f0a07fafc2b5f4a1636fd8bc940804 +F ext/session/session_common.tcl f4b7b59c617edf0c9b00d94cd93498d225d43837 F ext/session/sessionfault.test bef044d0952c0d62c31c8d2400be72c8684545cc -F ext/session/sqlite3session.c 9ccf68d542f4afc5dc14295d984bf37a7db6b936 +F ext/session/sqlite3session.c d630293057fcf4274451edec24c2745953ca042c F ext/session/sqlite3session.h 8e86f9eec3ed71f1f30eefbe810cbe5bc10b5aa9 F ext/session/test_session.c 187bd344c5ae9d5be85e22ef7c3010f0c17307ce F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220 @@ -1300,7 +1301,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 519054bb72e8f8977b11161c81b0e96ba7bca589 09a38bf665902834936d39341627ded88142e6ae -R 8892830f1d56f04b6b2e14d9642ea36b -U drh -Z 5694d275e23a4dea203ff0f897ed1e57 +P 54bec164ebeaf62d783352b3c4d0de8845394091 +R f80d0c3771ea18894e499ba6e9adad71 +U dan +Z e52febd1b018cb0f724ad3d4cfe4ef9d diff --git a/manifest.uuid b/manifest.uuid index 70a7baacb5..d8666bb556 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -54bec164ebeaf62d783352b3c4d0de8845394091 \ No newline at end of file +bdaf9575cd9ebb33dc5da4062a84bca79e7b0fec \ No newline at end of file