From a9605b912552c6d6b33c787917d79187fbf4c3ce Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 24 Mar 2011 16:53:57 +0000 Subject: [PATCH] Fix handling of schema changes mid-session. FossilOrigin-Name: 76d2d2ad3b2a5171393b7894f35f463ff284e53b --- ext/session/session3.test | 92 +++++++++++++++++++++++++++++++++++- ext/session/sqlite3session.c | 14 ++++-- manifest | 14 +++--- manifest.uuid | 2 +- 4 files changed, 110 insertions(+), 12 deletions(-) diff --git a/ext/session/session3.test b/ext/session/session3.test index e07032fccd..d0d2c31fa4 100644 --- a/ext/session/session3.test +++ b/ext/session/session3.test @@ -19,6 +19,7 @@ source $testdir/tester.tcl set testprefix session3 +#------------------------------------------------------------------------- # These tests - session3-1.* - verify that the session module behaves # correctly when confronted with a schema mismatch when applying a # changeset (in function sqlite3changeset_apply()). @@ -27,7 +28,6 @@ set testprefix session3 # session3-1.2.*: Table has wrong number of columns in target db. # session3-1.3.*: Table has wrong PK columns in target db. # - db close sqlite3_shutdown test_sqlite3_log log @@ -77,6 +77,96 @@ do_test 1.3.1 { set ::log } {SQLITE_SCHEMA {sqlite3changeset_apply(): primary key mismatch for table t1}} +#------------------------------------------------------------------------- +# These tests - session3-2.* - verify that the session module behaves +# correctly when the schema of an attached table is modified during the +# session. +# +# session3-2.1.*: Table is dropped midway through the session. +# session3-2.2.*: Table is dropped and recreated with a different # cols. +# session3-2.3.*: Table is dropped and recreated with a different PK. +# +# In all of these scenarios, the call to sqlite3session_changeset() will +# return SQLITE_SCHEMA. Also: +# +# session3-2.4.*: Table is dropped and recreated with an identical schema. +# In this case sqlite3session_changeset() returns SQLITE_OK. +# + +do_test 2.1 { + execsql { CREATE TABLE t2(a, b PRIMARY KEY) } + sqlite3session S db main + S attach t2 + execsql { + INSERT INTO t2 VALUES(1, 2); + DROP TABLE t2; + } + list [catch { S changeset } msg] $msg +} {1 SQLITE_SCHEMA} + +do_test 2.2.1 { + S delete + sqlite3session S db main + execsql { CREATE TABLE t2(a, b PRIMARY KEY, c) } + S attach t2 + execsql { + INSERT INTO t2 VALUES(1, 2, 3); + DROP TABLE t2; + CREATE TABLE t2(a, b PRIMARY KEY); + } + list [catch { S changeset } msg] $msg +} {1 SQLITE_SCHEMA} + +do_test 2.2.2 { + S delete + sqlite3session S db main + execsql { + DROP TABLE t2; + CREATE TABLE t2(a, b PRIMARY KEY, c); + } + S attach t2 + execsql { + INSERT INTO t2 VALUES(1, 2, 3); + DROP TABLE t2; + CREATE TABLE t2(a, b PRIMARY KEY, c, d); + } + list [catch { S changeset } msg] $msg +} {1 SQLITE_SCHEMA} + +do_test 2.3 { + S delete + sqlite3session S db main + execsql { + DROP TABLE t2; + CREATE TABLE t2(a, b PRIMARY KEY); + } + S attach t2 + execsql { + INSERT INTO t2 VALUES(1, 2); + DROP TABLE t2; + CREATE TABLE t2(a PRIMARY KEY, b, c); + } + list [catch { S changeset } msg] $msg +} {1 SQLITE_SCHEMA} + +do_test 2.4 { + S delete + sqlite3session S db main + execsql { + DROP TABLE t2; + CREATE TABLE t2(a, b PRIMARY KEY); + } + S attach t2 + execsql { + INSERT INTO t2 VALUES(1, 2); + DROP TABLE t2; + CREATE TABLE t2(a, b PRIMARY KEY); + } + list [catch { S changeset } msg] $msg +} {0 {}} + +S delete + catch { db close } catch { db2 close } diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index c64f567f90..ffc2e13f5e 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -1349,13 +1349,20 @@ int sqlite3session_changeset( for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ const char *zName = pTab->zName; - int nCol = pTab->nCol; /* Local copy of member variable */ - u8 *abPK = pTab->abPK; /* Local copy of member variable */ + int nCol; /* Number of columns in table */ + u8 *abPK; /* Primary key array */ + const char **azCol = 0; /* Table columns */ int i; /* Used to iterate through hash buckets */ sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ int nRewind = buf.nBuf; /* Initial size of write buffer */ int nNoop; /* Size of buffer after writing tbl header */ + /* Check the table schema is still Ok. */ + rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK); + if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ + rc = SQLITE_SCHEMA; + } + /* Write a table header */ sessionAppendByte(&buf, 'T', &rc); sessionAppendVarint(&buf, nCol, &rc); @@ -1365,7 +1372,7 @@ int sqlite3session_changeset( /* Build and compile a statement to execute: */ if( rc==SQLITE_OK ){ rc = sessionSelectStmt( - db, pSession->zDb, zName, nCol, pTab->azCol, abPK, &pSel); + db, pSession->zDb, zName, nCol, azCol, abPK, &pSel); } if( rc==SQLITE_OK && nCol!=sqlite3_column_count(pSel) ){ @@ -1407,6 +1414,7 @@ int sqlite3session_changeset( if( buf.nBuf==nNoop ){ buf.nBuf = nRewind; } + sqlite3_free(azCol); } } diff --git a/manifest b/manifest index e59c27fb75..1f7e7a7bdd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\shandling\sof\sschema\smismatches\sin\ssqlite3session.c\sso\sthat\sit\smatches\sthe\sdocs\sin\ssqlite3session.h. -D 2011-03-24T16:04:55 +C Fix\shandling\sof\sschema\schanges\smid-session. +D 2011-03-24T16:53:57 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -101,10 +101,10 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F ext/session/session1.test b2da15b9d727d7f4e5fe95599b32b92d93b5a970 F ext/session/session2.test 8da094318ac88953478c43d0bfb0aa723ee0e379 -F ext/session/session3.test b8b9ff7efcb19234892c406dba8bd56792560efe +F ext/session/session3.test c58ebb3273a23da9b5f4eb202d522aa759530a4c F ext/session/session_common.tcl fb91560b6dbd086010df8b3a137a452f1ac21a28 F ext/session/sessionfault.test d7e6154a30e85622d0733b1a1e3c63e9b8b7004b -F ext/session/sqlite3session.c cf91fe0efb0728c219c8bc2b2174a49758fbd3f8 +F ext/session/sqlite3session.c 33a5d4be9c22099aed8e7f6c80b63540953e84c2 F ext/session/sqlite3session.h 900d900bb6a827f84754fc252a05638e0f413a6e F ext/session/test_session.c e0f500ec5e20478afc2c7998133e8acea7ec5104 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 @@ -924,7 +924,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 54298ee5ed183d1f1c49524f25e8ae1407f3d4b5 -R 73cd0f1e5ce098769e9cee2c7d1f1ebc +P 506a0d7a710e1ff2f367821e73f5080fcf63fbc5 +R 3234ab73592ecae31c60c0a6f501bbfd U dan -Z 8a40e5171d2567a1ae6ca1b697973f9a +Z 29af2cd6e2d7044fdb214ebc342ad1ba diff --git a/manifest.uuid b/manifest.uuid index e8475cfcd0..5f9877e0ed 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -506a0d7a710e1ff2f367821e73f5080fcf63fbc5 \ No newline at end of file +76d2d2ad3b2a5171393b7894f35f463ff284e53b \ No newline at end of file