From: dan Date: Tue, 23 Aug 2016 19:02:21 +0000 (+0000) Subject: Add further tests for changebatch. And a fix to prevent a changeset from conflicting... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a8dee8df646b19de71ed288f088f3439209dfe1d;p=thirdparty%2Fsqlite.git Add further tests for changebatch. And a fix to prevent a changeset from conflicting with itself. FossilOrigin-Name: 506d6ff4b64c72d4ca65f0d15e1fdf8a132556bc --- diff --git a/ext/session/changebatch1.test b/ext/session/changebatch1.test index fc3f50ab4c..2fbe368947 100644 --- a/ext/session/changebatch1.test +++ b/ext/session/changebatch1.test @@ -19,6 +19,7 @@ ifcapable !session {finish_test; return} set testprefix changebatch1 + proc sql_to_changeset {method sql} { sqlite3session S db main S attach * @@ -37,13 +38,13 @@ proc do_changebatch_test {tn method args} { sqlite3changebatch cb db set i 1 foreach ::cs [lrange $C 0 end-1] { - do_test $tn.$i { cb add [set ::cs] } SQLITE_OK + set rc [cb add $::cs] + if {$rc!="SQLITE_OK"} { error "expected SQLITE_OK, got $rc (i=$i)" } incr i } set ::cs [lindex $C end] - do_test $tn.$i { cb add [set ::cs] } SQLITE_CONSTRAINT - + do_test $tn { cb add [set ::cs] } SQLITE_CONSTRAINT cb delete } @@ -94,6 +95,7 @@ foreach {tn testfunction} { do_execsql_test $tn.2.0 { CREATE TABLE x1(a, b PRIMARY KEY, c UNIQUE); CREATE TABLE x2(a PRIMARY KEY, b UNIQUE, c UNIQUE); + CREATE INDEX x1a ON x1(a); INSERT INTO x1 VALUES(1, 1, 'a'); INSERT INTO x1 VALUES(1, 2, 'b'); @@ -111,6 +113,53 @@ foreach {tn testfunction} { } { INSERT INTO x1 VALUES(1, 5, 'a'); } + + set L [list] + for {set i 1000} {$i < 10000} {incr i} { + lappend L "INSERT INTO x2 VALUES($i, $i, 'x' || $i)" + } + lappend L "DELETE FROM x2 WHERE b=1005" + $testfunction $tn.2.3 {*}$L + + execsql { INSERT INTO x1 VALUES('f', 'f', 'f') } + $testfunction $tn.2.4 { + INSERT INTO x2 VALUES('f', 'f', 'f'); + } { + INSERT INTO x1 VALUES('g', 'g', 'g'); + } { + DELETE FROM x1 WHERE b='f'; + } { + INSERT INTO x2 VALUES('g', 'g', 'g'); + } { + INSERT INTO x1 VALUES('f', 'f', 'f'); + } + + execsql { + DELETE FROM x1; + INSERT INTO x1 VALUES(1.5, 1.5, 1.5); + } + $testfunction $tn.2.5 { + DELETE FROM x1 WHERE b BETWEEN 1 AND 2; + } { + INSERT INTO x1 VALUES(2.5, 2.5, 2.5); + } { + INSERT INTO x1 VALUES(1.5, 1.5, 1.5); + } + + execsql { + DELETE FROM x2; + INSERT INTO x2 VALUES(X'abcd', X'1234', X'7890'); + INSERT INTO x2 VALUES(X'0000', X'0000', X'0000'); + } + breakpoint + $testfunction $tn.2.6 { + UPDATE x2 SET c = X'1234' WHERE a=X'abcd'; + INSERT INTO x2 VALUES(X'1234', X'abcd', X'7890'); + } { + DELETE FROM x2 WHERE b=X'0000'; + } { + INSERT INTO x2 VALUES(1, X'0000', NULL); + } } #------------------------------------------------------------------------- @@ -151,7 +200,23 @@ do_test 3.1.2 { cb delete } {} +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 4.0 { + CREATE TABLE t1(x, y, z, PRIMARY KEY(x, y), UNIQUE(z)); +} + +do_test 4.1 { + set c1 [sql_to_changeset fullchangeset { INSERT INTO t1 VALUES(1, 2, 3) }] + execsql { + DROP TABLE t1; + CREATE TABLE t1(w, x, y, z, PRIMARY KEY(x, y), UNIQUE(z)); + } + sqlite3changebatch cb db + list [catch { cb add $c1 } msg] $msg +} {1 SQLITE_RANGE} -finish_test +finish_test diff --git a/ext/session/changebatchfault.test b/ext/session/changebatchfault.test new file mode 100644 index 0000000000..209b60e0c8 --- /dev/null +++ b/ext/session/changebatchfault.test @@ -0,0 +1,42 @@ +# 2011 Mar 21 +# +# 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 changebatchfault + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c PRIMARY KEY, UNIQUE(a, b)); + INSERT INTO t1 VALUES('a', 'a', 'a'); + INSERT INTO t1 VALUES('b', 'b', 'b'); +} + +set ::c1 [changeset_from_sql { delete from t1 where c='a' }] +set ::c2 [changeset_from_sql { insert into t1 values('c', 'c', 'c') }] + +do_faultsim_test 1 -faults oom-* -body { + sqlite3changebatch cb db + cb add $::c1 + cb add $::c2 +} -test { + faultsim_test_result {0 SQLITE_OK} {1 SQLITE_NOMEM} + catch { cb delete } +} + + +finish_test diff --git a/ext/session/sqlite3changebatch.c b/ext/session/sqlite3changebatch.c index 186bcab99c..a31d04ff4e 100644 --- a/ext/session/sqlite3changebatch.c +++ b/ext/session/sqlite3changebatch.c @@ -154,10 +154,8 @@ static int cbAddIndex( } if( rc==SQLITE_OK ){ - int rc2; while( SQLITE_ROW==sqlite3_step(pIndexInfo) ){ nCol++; } - rc2 = sqlite3_reset(pIndexInfo); - if( rc==SQLITE_OK ) rc = rc2; + rc = sqlite3_reset(pIndexInfo); } pNew = (BatchIndex*)cbMalloc(&rc, sizeof(BatchIndex) + sizeof(int) * nCol); @@ -172,8 +170,7 @@ static int cbAddIndex( int j = sqlite3_column_int(pIndexInfo, 1); pNew->aiCol[i] = j; } - rc2 = sqlite3_reset(pIndexInfo); - if( rc==SQLITE_OK ) rc = rc2; + rc = sqlite3_reset(pIndexInfo); } if( rc==SQLITE_OK ){ @@ -187,6 +184,19 @@ static int cbAddIndex( return rc; } +/* +** Free the object passed as the first argument. +*/ +static void cbFreeTable(BatchTable *pTab){ + BatchIndex *pIdx; + BatchIndex *pIdxNext; + for(pIdx=pTab->pIdx; pIdx; pIdx=pIdxNext){ + pIdxNext = pIdx->pNext; + cbFree(pIdx); + } + cbFree(pTab); +} + /* ** Find or create the BatchTable object named zTab. */ @@ -232,6 +242,9 @@ static int cbFindTable( if( rc==SQLITE_OK ){ pRet->pNext = p->pTab; p->pTab = pRet; + }else{ + cbFreeTable(pRet); + pRet = 0; } } } @@ -240,6 +253,16 @@ static int cbFindTable( return rc; } +/* +** Extract value iVal from the changeset iterator passed as the first +** argument. Set *ppVal to point to the value before returning. +** +** This function attempts to extract the value using function xVal +** (which is always either sqlite3changeset_new or sqlite3changeset_old). +** If the call returns SQLITE_OK but does not supply an sqlite3_value* +** pointer, an attempt to extract the value is made using the xFallback +** function. +*/ static int cbGetChangesetValue( sqlite3_changeset_iter *pIter, int (*xVal)(sqlite3_changeset_iter*,int,sqlite3_value**), @@ -300,33 +323,33 @@ static int cbAddToHash( pNew->iIdxId = pIdx->iId; pNew->szRecord = sz; - for(i=0; rc==SQLITE_OK && inCol; i++){ + for(i=0; inCol; i++){ + int eType; sqlite3_value *pVal; rc = cbGetChangesetValue(pIter, xVal, xFallback, pIdx->aiCol[i], &pVal); - if( rc==SQLITE_OK ){ - int eType = sqlite3_value_type(pVal); - pNew->aRecord[iOut++] = eType; - switch( eType ){ - case SQLITE_INTEGER: { - sqlite3_int64 i64 = sqlite3_value_int64(pVal); - memcpy(&pNew->aRecord[iOut], &i64, 8); - iOut += 8; - break; - } - case SQLITE_FLOAT: { - double d64 = sqlite3_value_double(pVal); - memcpy(&pNew->aRecord[iOut], &d64, sizeof(double)); - iOut += sizeof(double); - break; - } + if( rc!=SQLITE_OK ) break; /* coverage: condition is never true */ + eType = sqlite3_value_type(pVal); + pNew->aRecord[iOut++] = eType; + switch( eType ){ + case SQLITE_INTEGER: { + sqlite3_int64 i64 = sqlite3_value_int64(pVal); + memcpy(&pNew->aRecord[iOut], &i64, 8); + iOut += 8; + break; + } + case SQLITE_FLOAT: { + double d64 = sqlite3_value_double(pVal); + memcpy(&pNew->aRecord[iOut], &d64, sizeof(double)); + iOut += sizeof(double); + break; + } - default: { - int nByte = sqlite3_value_bytes(pVal); - const char *z = (const char*)sqlite3_value_blob(pVal); - memcpy(&pNew->aRecord[iOut], z, nByte); - iOut += nByte; - break; - } + default: { + int nByte = sqlite3_value_bytes(pVal); + const char *z = (const char*)sqlite3_value_blob(pVal); + memcpy(&pNew->aRecord[iOut], z, nByte); + iOut += nByte; + break; } } } @@ -359,9 +382,10 @@ static int cbAddToHash( p->apHash[iHash] = pNew; p->nEntry++; } + }else{ + cbFree(pNew); } - p->iChangesetId++; return rc; } @@ -391,15 +415,18 @@ int sqlite3changebatch_add(sqlite3_changebatch *p, void *pBuf, int nBuf){ assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); rc = cbFindTable(p, zTab, &pTab); - for(pIdx=pTab->pIdx; pIdx && rc==SQLITE_OK; pIdx=pIdx->pNext){ - if( op==SQLITE_UPDATE && pIdx->bPk ) continue; - if( op==SQLITE_UPDATE || op==SQLITE_DELETE ){ - rc = cbAddToHash(p, pIter, pIdx, sqlite3changeset_old, 0, &bConf); - } - if( op==SQLITE_UPDATE || op==SQLITE_INSERT ){ - rc = cbAddToHash(p, pIter, pIdx, - sqlite3changeset_new, sqlite3changeset_old, &bConf - ); + assert( pTab || rc!=SQLITE_OK ); + if( pTab ){ + for(pIdx=pTab->pIdx; pIdx && rc==SQLITE_OK; pIdx=pIdx->pNext){ + if( op==SQLITE_UPDATE && pIdx->bPk ) continue; + if( op==SQLITE_UPDATE || op==SQLITE_DELETE ){ + rc = cbAddToHash(p, pIter, pIdx, sqlite3changeset_old, 0, &bConf); + } + if( op==SQLITE_UPDATE || op==SQLITE_INSERT ){ + rc = cbAddToHash(p, pIter, pIdx, + sqlite3changeset_new, sqlite3changeset_old, &bConf + ); + } } } if( rc!=SQLITE_OK ) break; @@ -412,6 +439,7 @@ int sqlite3changebatch_add(sqlite3_changebatch *p, void *pBuf, int nBuf){ if( rc==SQLITE_OK && bConf ){ rc = SQLITE_CONSTRAINT; } + p->iChangesetId++; return rc; } @@ -442,14 +470,8 @@ void sqlite3changebatch_delete(sqlite3_changebatch *p){ sqlite3changebatch_zero(p); for(pTab=p->pTab; pTab; pTab=pTabNext){ - BatchIndex *pIdx; - BatchIndex *pIdxNext; - for(pIdx=pTab->pIdx; pIdx; pIdx=pIdxNext){ - pIdxNext = pIdx->pNext; - cbFree(pIdx); - } pTabNext = pTab->pNext; - cbFree(pTab); + cbFreeTable(pTab); } cbFree(p); } diff --git a/manifest b/manifest index 4b3e6de352..3cea0f9b42 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings\sin\schangebatch. -D 2016-08-23T18:09:37.916 +C Add\sfurther\stests\sfor\schangebatch.\sAnd\sa\sfix\sto\sprevent\sa\schangeset\sfrom\sconflicting\swith\sitself. +D 2016-08-23T19:02:21.914 F Makefile.in cfd8fb987cd7a6af046daa87daa146d5aad0e088 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a @@ -281,7 +281,8 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 -F ext/session/changebatch1.test f3e5462189ebe238b57ddf31f17e5f6cb410f895 +F ext/session/changebatch1.test 9ceaa8f7b2a505933e250fbe6cbc550e4ce1e59d +F ext/session/changebatchfault.test be49c793219bf387ad692a60856b921f0854ad6d F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a F ext/session/session1.test 98f384736e2bc21ccf5ed81bdadcff4ad863393b F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0 @@ -301,7 +302,7 @@ F ext/session/sessionG.test 01ef705096a9d3984eebdcca79807a211dee1b60 F ext/session/session_common.tcl a1293167d14774b5e728836720497f40fe4ea596 F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7 F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0 -F ext/session/sqlite3changebatch.c 72ec2f5c70af4e9e938222a98962bc05b82e9bf4 +F ext/session/sqlite3changebatch.c 4b4fe1d52587e5fdb28930466409712f0e4b619d F ext/session/sqlite3changebatch.h 50a302e4fc535324309607b13a1993bca074758b F ext/session/sqlite3session.c e5591f76aea6058720e04f78ae9e88487eb56c6b F ext/session/sqlite3session.h c772b5440f41af44631891aa7f352e9a44b740ad @@ -1514,7 +1515,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P efa761b2f509844b9212dd20bf0d082c6338e83f -R 7f5bf9af3be1c169a39e0edb328bafbb -U drh -Z e5dc9f2e44b6adaa79d5e6bc2fc1ab5e +P a721a738184d914fcde3f5684099984a9373dff3 +R b3c5ba41110022813f99ffae5c67351c +U dan +Z 78075b3679b308d5ec26925a2eace0fc diff --git a/manifest.uuid b/manifest.uuid index ad7a6d4e5d..96566a509e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a721a738184d914fcde3f5684099984a9373dff3 \ No newline at end of file +506d6ff4b64c72d4ca65f0d15e1fdf8a132556bc \ No newline at end of file