Update the ota extension so that it can be used to update tables with external PRIMARY KEY indexes.
FossilOrigin-Name: 55066a1171cbd3077f5e6c8ceb2745e810d9476e
This commit is contained in:
parent
54ef517012
commit
268c0f8844
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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; i<nCol; i++){
|
||||
int iCol = aiCol ? aiCol[i] : i;
|
||||
zList = sqlite3_mprintf("%z%s%s", zList, zSep, pIter->azTblCol[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 "
|
||||
"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_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
|
||||
, 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;
|
||||
|
18
manifest
18
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
|
||||
|
@ -1 +1 @@
|
||||
556c3de53ad33d11d33ec794345c2100aa76f3e1
|
||||
55066a1171cbd3077f5e6c8ceb2745e810d9476e
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user