From: dan Date: Thu, 20 Nov 2014 17:37:08 +0000 (+0000) Subject: Update the ota extension so that it can be used to update tables with external PRIMAR... X-Git-Tag: version-3.8.11~252^2~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=268c0f8844440db27c1f455ff45261515c93661e;p=thirdparty%2Fsqlite.git Update the ota extension so that it can be used to update tables with external PRIMARY KEY indexes. FossilOrigin-Name: 55066a1171cbd3077f5e6c8ceb2745e810d9476e --- diff --git a/ext/ota/ota1.test b/ext/ota/ota1.test index deed62f6c8..e6b50c5906 100644 --- a/ext/ota/ota1.test +++ b/ext/ota/ota1.test @@ -136,6 +136,18 @@ foreach {tn2 cmd} {1 run_ota 2 step_ota 3 step_ota_uri} { CREATE INDEX i2 ON t1(c, b); CREATE INDEX i3 ON t1(a, b, c, a, b, c); } + + 8 { + CREATE TABLE t1(a PRIMARY KEY, b, c); + CREATE INDEX i1 ON t1(b, c); + CREATE INDEX i2 ON t1(c, b); + CREATE INDEX i3 ON t1(a, b, c, a, b, c); + } + + 9 { + CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c)); + CREATE INDEX i1 ON t1(b); + } } { reset_db execsql $schema @@ -160,6 +172,11 @@ foreach {tn2 cmd} {1 run_ota 2 step_ota 3 step_ota_uri} { #------------------------------------------------------------------------- # Check that an OTA cannot be applied to a table that has no PK. # +# UPDATE: At one point OTA required that all tables featured either +# explicit IPK columns or were declared WITHOUT ROWID. This has been +# relaxed so that external PRIMARY KEYs on tables with automatic rowids +# are now allowed. +# reset_db create_ota1 ota.db do_execsql_test 2.1 { CREATE TABLE t1(a, b, c) } @@ -170,16 +187,15 @@ do_test 2.2 { do_test 2.3 { list [catch { ota close } msg] $msg } {1 {SQLITE_ERROR - table t1 has no PRIMARY KEY}} - reset_db do_execsql_test 2.4 { CREATE TABLE t1(a PRIMARY KEY, b, c) } do_test 2.5 { sqlite3ota ota test.db ota.db ota step -} {SQLITE_ERROR} +} {SQLITE_OK} do_test 2.6 { list [catch { ota close } msg] $msg -} {1 {SQLITE_ERROR - table t1 has no PRIMARY KEY}} +} {0 SQLITE_OK} #------------------------------------------------------------------------- # Check that if a UNIQUE constraint is violated the current and all @@ -198,6 +214,16 @@ foreach {tn errcode errmsg schema} { INSERT INTO t1 VALUES(4, 2, 'three'); } + 3 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.a" { + CREATE TABLE t1(a PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(3, 2, 1); + } + + 4 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.c" { + CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE); + INSERT INTO t1 VALUES(4, 2, 'three'); + } + } { reset_db execsql $schema @@ -242,6 +268,12 @@ foreach {tn2 cmd} {1 run_ota 2 step_ota} { CREATE INDEX i2 ON t1(c, b); CREATE INDEX i3 ON t1(c, b, c); } + 5 { + CREATE TABLE t1(a INT PRIMARY KEY, b, c); + CREATE INDEX i1 ON t1(b); + CREATE INDEX i2 ON t1(c, b); + CREATE INDEX i3 ON t1(c, b, c); + } } { reset_db execsql $schema @@ -293,6 +325,15 @@ foreach {tn2 cmd} {1 run_ota 2 step_ota} { CREATE INDEX i5 ON t1(c); CREATE INDEX i6 ON t1(c, b); } + 4 { + CREATE TABLE t1(a 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 diff --git a/ext/ota/ota7.test b/ext/ota/ota7.test index 099d3da732..a4ee6b41ad 100644 --- a/ext/ota/ota7.test +++ b/ext/ota/ota7.test @@ -58,6 +58,7 @@ do_execsql_test 1.2 { # foreach {tn tbl} { 1 { CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID } + 2 { CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)) } } { reset_db diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c index 88fe45d392..3b02750866 100644 --- a/ext/ota/sqlite3ota.c +++ b/ext/ota/sqlite3ota.c @@ -102,6 +102,7 @@ struct OtaObjIter { int nTblCol; /* Size of azTblCol[] array */ char **azTblCol; /* Array of quoted column names */ unsigned char *abTblPk; /* Array of flags - true for PK columns */ + unsigned char bRowid; /* True for implicit IPK tables */ /* Output variables. zTbl==0 implies EOF. */ int bCleanup; /* True in "cleanup" state */ @@ -225,6 +226,7 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){ pIter->nTblCol = 0; sqlite3_free(pIter->zMask); pIter->zMask = 0; + pIter->bRowid = 0; } /* @@ -391,8 +393,8 @@ static int otaMPrintfExec(sqlite3ota *p, const char *zFmt, ...){ /* ** If they are not already populated, populate the pIter->azTblCol[], -** pIter->abTblPk[] and pIter->nTblCol variables according to the table -** that the iterator currently points to. +** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to +** the table that the iterator currently points to. ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. If ** an error does occur, an error code and error message are also left in @@ -406,6 +408,7 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ int bSeenPk = 0; int rc2; /* sqlite3_finalize() return value */ + assert( pIter->bRowid==0 ); zSql = sqlite3_mprintf("PRAGMA main.table_info(%Q)", pIter->zTbl); p->rc = prepareFreeAndCollectError(p->db, &pStmt, &p->zErrmsg, zSql); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ @@ -422,8 +425,10 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ if( p->rc==SQLITE_OK ){ const char *zName = (const char*)sqlite3_column_text(pStmt, 1); - pIter->abTblPk[nCol] = sqlite3_column_int(pStmt, 5); - if( pIter->abTblPk[nCol] ) bSeenPk = 1; + int iPk = sqlite3_column_int(pStmt, 5); + pIter->abTblPk[nCol] = (iPk!=0); + if( iPk ) bSeenPk = 1; + if( iPk<0 ) pIter->bRowid = 1; pIter->azTblCol[nCol] = otaQuoteName(zName); if( pIter->azTblCol[nCol]==0 ) p->rc = SQLITE_NOMEM; nCol++; @@ -489,7 +494,8 @@ static char *otaObjIterGetCollist( int i; for(i=0; iazTblCol[iCol]); + char *zCol = (iCol>=0 ? pIter->azTblCol[iCol] : "ota_rowid"); + zList = sqlite3_mprintf("%z%s%s", zList, zSep, zCol); if( zList && azCollate ){ zList = sqlite3_mprintf("%z COLLATE %Q", zList, azCollate[i]); } @@ -520,6 +526,11 @@ static char *otaObjIterGetOldlist( break; } } + + /* For a table with implicit rowids, append "old._rowid_" to the list. */ + if( pIter->bRowid ){ + zList = sqlite3_mprintf("%z, %s._rowid_", zList, zObj); + } } return zList; } @@ -648,20 +659,29 @@ static int otaObjIterPrepareAll( /* Create the SELECT statement to read keys in sorted order */ zCollist = otaObjIterGetCollist(p, pIter, pIter->nCol, aiCol, azColl); if( p->rc==SQLITE_OK ){ - p->rc = prepareFreeAndCollectError(p->db, &pIter->pSelect, pz, - sqlite3_mprintf( + char *zSql; + if( pIter->bRowid ){ + zSql = sqlite3_mprintf( + "SELECT %s, ota_control FROM ota.'ota_tmp_%q' ORDER BY %s%s", + zCollist, pIter->zTbl, + zCollist, zLimit + ); + }else{ + zSql = sqlite3_mprintf( "SELECT %s, ota_control FROM ota.'data_%q' " "WHERE typeof(ota_control)='integer' AND ota_control!=1 " - "UNION ALL " + "UNION ALL " "SELECT %s, ota_control FROM ota.'ota_tmp_%q' " "ORDER BY %s%s", zCollist, pIter->zTbl, zCollist, pIter->zTbl, zCollist, zLimit - ) - ); + ); + } + p->rc = prepareFreeAndCollectError(p->db, &pIter->pSelect, pz, zSql); } }else{ + const char *zOtaRowid = (pIter->bRowid ? ", ota_rowid" : ""); char *zBindings = otaObjIterGetBindlist(p, pIter->nTblCol); char *zWhere = otaObjIterGetWhere(p, pIter); char *zOldlist = otaObjIterGetOldlist(p, pIter, "old"); @@ -697,33 +717,44 @@ static int otaObjIterPrepareAll( ); } - if( p->rc==SQLITE_OK ){ + /* Create the ota_tmp_xxx table and the triggers to populate it. */ + otaMPrintfExec(p, + "CREATE TABLE IF NOT EXISTS ota.'ota_tmp_%q' AS " + "SELECT *%s 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%s) VALUES(2, %s);" + "END;" + + "CREATE TEMP TRIGGER ota_update1_%q BEFORE UPDATE ON main.%Q " + "BEGIN " + " INSERT INTO 'ota_tmp_%q'(ota_control, %s%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%s) VALUES(3, %s);" + "END;" + , pIter->zTbl, (pIter->bRowid ? ", 0 AS ota_rowid" : ""), + pIter->zTbl, + pIter->zTbl, pIter->zTbl, pIter->zTbl, zCollist, zOtaRowid, zOldlist, + pIter->zTbl, pIter->zTbl, pIter->zTbl, zCollist, zOtaRowid, zOldlist, + pIter->zTbl, pIter->zTbl, pIter->zTbl, zCollist, zOtaRowid, zNewlist + ); + if( pIter->bRowid ){ 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;" - - "CREATE TEMP TRIGGER ota_update1_%q BEFORE UPDATE ON main.%Q " + "CREATE TEMP TRIGGER ota_insert_%q AFTER INSERT ON main.%Q " "BEGIN " - " INSERT INTO 'ota_tmp_%q'(ota_control, %s) VALUES(2, %s);" + " INSERT INTO 'ota_tmp_%q'(ota_control, %s, ota_rowid)" + " VALUES(0, %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 + , 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; diff --git a/manifest b/manifest index 57046725ee..78a7f550e6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\ssupport\szipvfs\sin\spass-through\smode. -D 2014-11-20T15:11:12.852 +C Update\sthe\sota\sextension\sso\sthat\sit\scan\sbe\sused\sto\supdate\stables\swith\sexternal\sPRIMARY\sKEY\sindexes. +D 2014-11-20T17:37:08.997 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -124,15 +124,15 @@ F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/ota/README.txt 78d4a9f78f567d4bf826cf0f02df6254902562ca F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91 -F ext/ota/ota1.test 98deadd0c67ca634bd3ce30ef063a3bb6534a029 +F ext/ota/ota1.test a8f9d89c9b2d381a663bcedaa5dd5952cdbd1231 F ext/ota/ota2.test 4568c2671d19dbde789fb9091d727a2e94880128 F ext/ota/ota3.test 215dd4a8e238567e0f890a5139b6fdf5494ef311 F ext/ota/ota4.test 60f897f329a6782ef2f24862640acf3c52e48077 F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb F ext/ota/ota6.test 82f1f757ec9b2ad07d6de4060b8e3ba8e44dfdd3 -F ext/ota/ota7.test 36e740da2b67cc086ff9f2975d2929b8beaa1016 +F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a F ext/ota/otafault.test be02466863015a583cc0ceb6aca871a5e6f7a71b -F ext/ota/sqlite3ota.c c2b34913954720200f1f33556df25fe55387c531 +F ext/ota/sqlite3ota.c 2c31a56890e915e13eb5d6ced02325e1f4db7487 F ext/ota/sqlite3ota.h 7b20abe9247d292429d00f0a5c237ff6e0dc0196 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b @@ -233,7 +233,7 @@ F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c e412cb585f777c840ddce0500eddc5c6043c2bb5 -F src/pragma.c 92343541fc50d9fd30eb734f77d43d7636521e7e +F src/pragma.c 272b122a873fc756e999c319f8e81de55ef39d5c F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196 F src/printf.c 6b79bbd063dcbadca4cf617a4cde255bcc13ea64 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece @@ -1217,7 +1217,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 712d413d29950b19d4afb18cfcf9d3afb302d0a0 -R 2621b5f3be6f418323e840a9284ff98b +P 556c3de53ad33d11d33ec794345c2100aa76f3e1 +R c3a23811c2315fa65ee1bcdda07f2567 U dan -Z 3bf4b5d8555904656fb3130ef9899e9e +Z eebecee2ceb200b37a4bd343197c1b04 diff --git a/manifest.uuid b/manifest.uuid index ef96f551b3..8e90b7e445 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -556c3de53ad33d11d33ec794345c2100aa76f3e1 \ No newline at end of file +55066a1171cbd3077f5e6c8ceb2745e810d9476e \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index f1c44bdb13..5b89237014 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1526,10 +1526,9 @@ void sqlite3Pragma( }else if( pPk==0 ){ k = 1; }else{ + for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} if( (db->flags & SQLITE_OtaMode) && HasRowid(pTab) ){ - k = 0; - }else{ - for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} + k = -1 * k; } } sqlite3VdbeAddOp2(v, OP_Integer, k, 6);