From: dan Date: Mon, 8 Sep 2014 17:50:35 +0000 (+0000) Subject: Add support for update statements to sqlite3ota.c. X-Git-Tag: version-3.8.11~252^2~108 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a690402b4cab21b9243a206134d1e2eed41f605a;p=thirdparty%2Fsqlite.git Add support for update statements to sqlite3ota.c. FossilOrigin-Name: e109b27e4d66b83e1a804e7556d9c91aa37fea28 --- diff --git a/ext/ota/ota1.test b/ext/ota/ota1.test index 22b8fa66cd..917d1d2c9e 100644 --- a/ext/ota/ota1.test +++ b/ext/ota/ota1.test @@ -36,6 +36,8 @@ proc create_ota1 {filename} { # # CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); # +# This OTA includes both insert and delete operations. +# proc create_ota4 {filename} { forcedelete $filename sqlite3 ota1 $filename @@ -50,6 +52,25 @@ proc create_ota4 {filename} { return $filename } +# Create a simple OTA database. That expects to write to a table: +# +# CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d); +# +# This OTA includes update statements. +# +proc create_ota5 {filename} { + forcedelete $filename + sqlite3 ota5 $filename + ota5 eval { + CREATE TABLE data_t1(a, b, c, d, ota_control); + INSERT INTO data_t1 VALUES(1, NULL, NULL, 5, '...x'); -- SET d = 5 + INSERT INTO data_t1 VALUES(2, NULL, 10, 5, '..xx'); -- SET c=10, d = 5 + INSERT INTO data_t1 VALUES(3, 11, NULL, NULL, '.x..'); -- SET b=11 + } + ota5 close + return $filename +} + # Run the OTA in file $ota on target database $target until completion. # proc run_ota {target ota} { @@ -224,6 +245,47 @@ foreach {tn2 cmd} {1 run_ota 2 step_ota} { } } +#------------------------------------------------------------------------- +# +foreach {tn2 cmd} {1 run_ota 2 step_ota} { + foreach {tn schema} { + 1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d); + } + 2 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d); + CREATE INDEX i1 ON t1(d); + CREATE INDEX i2 ON t1(d, c); + CREATE INDEX i3 ON t1(d, c, b); + CREATE INDEX i4 ON t1(b); + CREATE INDEX i5 ON t1(c); + CREATE INDEX i6 ON t1(c, b); + } + } { + reset_db + execsql $schema + execsql { + INSERT INTO t1 VALUES(1, 2, 3, 4); + INSERT INTO t1 VALUES(2, 5, 6, 7); + INSERT INTO t1 VALUES(3, 8, 9, 10); + } + + do_test 5.$tn2.$tn.1 { + create_ota5 ota.db + $cmd test.db ota.db + } {SQLITE_DONE} + + do_execsql_test 5.$tn2.$tn.2 { + SELECT * FROM t1 ORDER BY a ASC; + } { + 1 2 3 5 + 2 5 10 5 + 3 11 9 10 + } + + do_execsql_test 5.$tn2.$tn.3 { PRAGMA integrity_check } ok + } +} finish_test diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c index 62b1c4ab34..fcf0c8b9fd 100644 --- a/ext/ota/sqlite3ota.c +++ b/ext/ota/sqlite3ota.c @@ -78,6 +78,10 @@ struct OtaObjIter { sqlite3_stmt *pSelect; /* Source data */ sqlite3_stmt *pInsert; /* Statement for INSERT operations */ sqlite3_stmt *pDelete; /* Statement for DELETE ops */ + + /* Last UPDATE used (for PK b-tree updates only), or NULL. */ + char *zMask; /* Copy of update mask used with pUpdate */ + sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */ }; /* @@ -179,6 +183,24 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){ pIter->azTblCol = 0; pIter->abTblPk = 0; pIter->nTblCol = 0; + sqlite3_free(pIter->zMask); + pIter->zMask = 0; +} + +/* +** Finalize all statements and free all allocations that are specific to +** the current object (table/index pair). +*/ +static void otaObjIterClearStatements(OtaObjIter *pIter){ + sqlite3_finalize(pIter->pSelect); + sqlite3_finalize(pIter->pInsert); + sqlite3_finalize(pIter->pDelete); + sqlite3_finalize(pIter->pUpdate); + pIter->pSelect = 0; + pIter->pInsert = 0; + pIter->pDelete = 0; + pIter->pUpdate = 0; + pIter->nCol = 0; } /* @@ -186,11 +208,9 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){ ** as the only argument. */ static void otaObjIterFinalize(OtaObjIter *pIter){ + otaObjIterClearStatements(pIter); sqlite3_finalize(pIter->pTblIter); sqlite3_finalize(pIter->pIdxIter); - sqlite3_finalize(pIter->pSelect); - sqlite3_finalize(pIter->pInsert); - sqlite3_finalize(pIter->pDelete); otaObjIterFreeCols(pIter); memset(pIter, 0, sizeof(OtaObjIter)); } @@ -208,13 +228,7 @@ static int otaObjIterNext(sqlite3ota *p, OtaObjIter *pIter){ if( rc==SQLITE_OK ){ /* Free any SQLite statements used while processing the previous object */ - sqlite3_finalize(pIter->pSelect); - sqlite3_finalize(pIter->pInsert); - sqlite3_finalize(pIter->pDelete); - pIter->pSelect = 0; - pIter->pInsert = 0; - pIter->pDelete = 0; - pIter->nCol = 0; + otaObjIterClearStatements(pIter); if( pIter->bCleanup ){ otaObjIterFreeCols(pIter); @@ -412,15 +426,16 @@ static char *otaObjIterGetCollist( static char *otaObjIterGetOldlist( sqlite3ota *p, - OtaObjIter *pIter + OtaObjIter *pIter, + const char *zObj ){ char *zList = 0; if( p->rc==SQLITE_OK ){ - const char *zSep = ""; + const char *zS = ""; int i; for(i=0; inTblCol; i++){ - zList = sqlite3_mprintf("%z%sold.%s", zList, zSep, pIter->azTblCol[i]); - zSep = ", "; + zList = sqlite3_mprintf("%z%s%s.%s", zList, zS, zObj, pIter->azTblCol[i]); + zS = ", "; if( zList==0 ){ p->rc = SQLITE_NOMEM; break; @@ -440,7 +455,8 @@ static char *otaObjIterGetWhere( int i; for(i=0; inTblCol; i++){ if( pIter->abTblPk[i] ){ - zList = sqlite3_mprintf("%z%s%s=?", zList, zSep, pIter->azTblCol[i]); + const char *zCol = pIter->azTblCol[i]; + zList = sqlite3_mprintf("%z%s%s=?%d", zList, zSep, zCol, i+1); zSep = " AND "; if( zList==0 ){ p->rc = SQLITE_NOMEM; @@ -452,6 +468,44 @@ static char *otaObjIterGetWhere( return zList; } +/* +** The SELECT statement iterating through the keys for the current object +** (p->objiter.pSelect) currently points to a valid row. However, there +** is something wrong with the ota_control value in the ota_control value +** stored in the (p->nCol+1)'th column. Set the error code and error message +** of the OTA handle to something reflecting this. +*/ +static void otaBadControlError(sqlite3ota *p){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("Invalid ota_control value"); +} + +static char *otaObjIterGetSetlist( + sqlite3ota *p, + OtaObjIter *pIter, + const char *zMask +){ + char *zList = 0; + if( p->rc==SQLITE_OK ){ + int i; + + if( strlen(zMask)!=pIter->nTblCol ){ + otaBadControlError(p); + }else{ + const char *zSep = ""; + for(i=0; inTblCol; i++){ + if( zMask[i]=='x' ){ + zList = sqlite3_mprintf("%z%s%s=?%d", + zList, zSep, pIter->azTblCol[i], i+1 + ); + zSep = ", "; + } + } + } + } + return zList; +} + static char *otaObjIterGetBindlist(sqlite3ota *p, int nBind){ char *zRet = 0; if( p->rc==SQLITE_OK ){ @@ -513,6 +567,7 @@ static int otaObjIterPrepareAll( p->rc = prepareFreeAndCollectError(p->db, &pIter->pSelect, pz, sqlite3_mprintf( "SELECT %s, ota_control FROM ota.'data_%q' " + "WHERE typeof(ota_control)='integer' AND ota_control!=1 " "UNION ALL " "SELECT %s, ota_control FROM ota.'ota_tmp_%q' " "ORDER BY %s%s", @@ -525,7 +580,8 @@ static int otaObjIterPrepareAll( }else{ char *zBindings = otaObjIterGetBindlist(p, pIter->nTblCol); char *zWhere = otaObjIterGetWhere(p, pIter); - char *zOldlist = otaObjIterGetOldlist(p, pIter); + char *zOldlist = otaObjIterGetOldlist(p, pIter, "old"); + char *zNewlist = otaObjIterGetOldlist(p, pIter, "new"); zCollist = otaObjIterGetCollist(p, pIter, pIter->nTblCol, 0); pIter->nCol = pIter->nTblCol; @@ -561,17 +617,43 @@ static int otaObjIterPrepareAll( otaMPrintfExec(p, "CREATE TABLE IF NOT EXISTS ota.'ota_tmp_%q' AS " "SELECT * FROM ota.'data_%q' WHERE 0;" + "CREATE TEMP TRIGGER ota_delete_%q BEFORE DELETE ON main.%Q " "BEGIN " " INSERT INTO 'ota_tmp_%q'(ota_control, %s) VALUES(2, %s);" "END;" - , pIter->zTbl, pIter->zTbl, pIter->zTbl, pIter->zTbl, pIter->zTbl, - zCollist, zOldlist + + "CREATE TEMP TRIGGER ota_update1_%q BEFORE UPDATE ON main.%Q " + "BEGIN " + " INSERT INTO 'ota_tmp_%q'(ota_control, %s) VALUES(2, %s);" + "END;" + + "CREATE TEMP TRIGGER ota_update2_%q AFTER UPDATE ON main.%Q " + "BEGIN " + " INSERT INTO 'ota_tmp_%q'(ota_control, %s) VALUES(3, %s);" + "END;" + + , pIter->zTbl, pIter->zTbl, + pIter->zTbl, pIter->zTbl, pIter->zTbl, zCollist, zOldlist, + pIter->zTbl, pIter->zTbl, pIter->zTbl, zCollist, zOldlist, + pIter->zTbl, pIter->zTbl, pIter->zTbl, zCollist, zNewlist ); } + /* Allocate space required for the zMask field. */ + if( p->rc==SQLITE_OK ){ + int nMask = pIter->nTblCol+1; + pIter->zMask = (char*)sqlite3_malloc(nMask); + if( pIter->zMask==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + memset(pIter->zMask, 0, nMask); + } + } + sqlite3_free(zWhere); sqlite3_free(zOldlist); + sqlite3_free(zNewlist); sqlite3_free(zBindings); } sqlite3_free(zCollist); @@ -584,18 +666,39 @@ static int otaObjIterPrepareAll( #define OTA_INSERT 1 #define OTA_DELETE 2 #define OTA_IDX_DELETE 3 -#define OTA_UPDATE 4 +#define OTA_IDX_INSERT 4 +#define OTA_UPDATE 5 -/* -** The SELECT statement iterating through the keys for the current object -** (p->objiter.pSelect) currently points to a valid row. However, there -** is something wrong with the ota_control value in the ota_control value -** stored in the (p->nCol+1)'th column. Set the error code and error message -** of the OTA handle to something reflecting this. -*/ -static void otaBadControlError(sqlite3ota *p){ - p->rc = SQLITE_ERROR; - p->zErrmsg = sqlite3_mprintf("Invalid ota_control value"); +static int otaGetUpdateStmt( + sqlite3ota *p, + OtaObjIter *pIter, + const char *zMask, + sqlite3_stmt **ppStmt +){ + if( pIter->pUpdate && strcmp(zMask, pIter->zMask)==0 ){ + *ppStmt = pIter->pUpdate; + }else{ + char *zWhere = otaObjIterGetWhere(p, pIter); + char *zSet = otaObjIterGetSetlist(p, pIter, zMask); + char *zUpdate = 0; + sqlite3_finalize(pIter->pUpdate); + pIter->pUpdate = 0; + if( p->rc==SQLITE_OK ){ + zUpdate = sqlite3_mprintf("UPDATE %Q SET %s WHERE %s", + pIter->zTbl, zSet, zWhere + ); + p->rc = prepareFreeAndCollectError( + p->db, &pIter->pUpdate, &p->zErrmsg, zUpdate + ); + *ppStmt = pIter->pUpdate; + } + if( p->rc==SQLITE_OK ){ + memcpy(pIter->zMask, zMask, pIter->nTblCol); + } + sqlite3_free(zWhere); + sqlite3_free(zSet); + } + return p->rc; } /* @@ -628,6 +731,8 @@ static int otaStepType(sqlite3ota *p, const char **pzMask){ res = OTA_DELETE; }else if( iVal==2 ){ res = OTA_IDX_DELETE; + }else if( iVal==3 ){ + res = OTA_IDX_INSERT; } break; } @@ -670,33 +775,43 @@ static int otaStep(sqlite3ota *p){ if( pIter->zIdx==0 && eType==OTA_IDX_DELETE ){ otaBadControlError(p); } - else if( eType==OTA_INSERT || eType==OTA_IDX_DELETE ){ + else if( + eType==OTA_INSERT + || eType==OTA_DELETE + || eType==OTA_IDX_DELETE + || eType==OTA_IDX_INSERT + ){ sqlite3_stmt *pWriter; + assert( eType!=OTA_UPDATE ); + assert( eType!=OTA_DELETE || pIter->zIdx==0 ); + + if( eType==OTA_IDX_DELETE || eType==OTA_DELETE ){ + pWriter = pIter->pDelete; + }else{ + pWriter = pIter->pInsert; + } - pWriter = (eType==OTA_INSERT)?pIter->pInsert:pIter->pDelete; for(i=0; inCol; i++){ + if( eType==SQLITE_DELETE && pIter->zIdx==0 && pIter->abTblPk[i]==0 ){ + continue; + } sqlite3_value *pVal = sqlite3_column_value(pIter->pSelect, i); sqlite3_bind_value(pWriter, i+1, pVal); } sqlite3_step(pWriter); p->rc = resetAndCollectError(pWriter, &p->zErrmsg); - } - else if( eType==OTA_DELETE && pIter->zIdx==0 ){ - int iVar = 1; - assert( pIter->zIdx==0 ); - assert( pIter->nCol==pIter->nTblCol ); - for(i=0; inCol; i++){ - if( pIter->abTblPk[i] ){ + }else if( eType==OTA_UPDATE ){ + sqlite3_stmt *pUpdate = 0; + otaGetUpdateStmt(p, pIter, zMask, &pUpdate); + if( pUpdate ){ + for(i=0; inCol; i++){ sqlite3_value *pVal = sqlite3_column_value(pIter->pSelect, i); - sqlite3_bind_value(pIter->pDelete, iVar++, pVal); + sqlite3_bind_value(pUpdate, i+1, pVal); } + sqlite3_step(pUpdate); + p->rc = resetAndCollectError(pUpdate, &p->zErrmsg); } - sqlite3_step(pIter->pDelete); - p->rc = resetAndCollectError(pIter->pDelete, &p->zErrmsg); - }else if( eType==OTA_UPDATE ){ - p->rc = SQLITE_ERROR; - p->zErrmsg = sqlite3_mprintf("not yet"); }else{ /* no-op */ assert( eType==OTA_DELETE && pIter->zIdx ); @@ -718,7 +833,7 @@ int sqlite3ota_step(sqlite3ota *p){ /* Clean up the ota_tmp_xxx table for the previous table. It ** cannot be dropped as there are currently active SQL statements. ** But the contents can be deleted. */ - otaMPrintfExec(p, "DELETE FROM ota.'ota_tmp_%q'", pIter->zTbl); + // otaMPrintfExec(p, "DELETE FROM ota.'ota_tmp_%q'", pIter->zTbl); }else{ otaObjIterPrepareAll(p, pIter, 0); diff --git a/manifest b/manifest index 46bc695b1a..35c6c48a27 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssupport\sfor\sdelete\soperations\sto\sthe\sota\sextension. -D 2014-09-06T20:19:38.006 +C Add\ssupport\sfor\supdate\sstatements\sto\ssqlite3ota.c. +D 2014-09-08T17:50:35.158 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -122,9 +122,9 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95 F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/ota/ota.c d37097e92a005d3915883adefbb93019ea6f8841 -F ext/ota/ota1.test 47317179125b5e65289a9f59753c9f895186e6d5 +F ext/ota/ota1.test fe0bb8acf0caef6c19937b84c6547b788342610d F ext/ota/ota2.test 13f76922446c62ed96192e938b8e625ebf0142fa -F ext/ota/sqlite3ota.c ceb0f77dc6a958d299f532319f6477e5599dc59d +F ext/ota/sqlite3ota.c 3697f6db2d51d5f7c0f0306fe94514785361e521 F ext/ota/sqlite3ota.h 545f0008b5f02f2595899cb9841caddada5c17c0 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b @@ -1198,7 +1198,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 3c2f4a078132992e33cc675173c84f8385af9cb5 -R eeedfe1c92df64758f3e97de2d55d43b +P f988234ba54d7c667f7deef1d04beed4e7fe6182 +R c23b09bc3993f39690d272fa85636507 U dan -Z 3317be7135040205f21e9375db1283ea +Z 28e28dd83293020abb0c0fb47ae5ab2c diff --git a/manifest.uuid b/manifest.uuid index 457a56e402..09501cef43 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f988234ba54d7c667f7deef1d04beed4e7fe6182 \ No newline at end of file +e109b27e4d66b83e1a804e7556d9c91aa37fea28 \ No newline at end of file