From 75fda9b39558eb826aa1d3623e7f4bd4e4923ba7 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 3 Feb 2015 15:56:08 +0000 Subject: [PATCH] Remove "PRAGMA ota_mode". FossilOrigin-Name: 1c111447a07687c30ed4ad5a6c27a169c85b7ea6 --- ext/ota/ota3.test | 52 ++++- ext/ota/ota4.test | 105 ---------- ext/ota/sqlite3ota.c | 478 ++++++++++++++++++++++--------------------- manifest | 38 ++-- manifest.uuid | 2 +- src/btree.c | 3 +- src/delete.c | 3 - src/insert.c | 13 -- src/main.c | 39 ++++ src/pragma.c | 13 +- src/sqlite.h.in | 63 +----- src/sqliteInt.h | 6 - src/test1.c | 2 +- src/trigger.c | 8 +- src/vdbeblob.c | 179 ---------------- tool/mkpragmatab.tcl | 5 - 16 files changed, 358 insertions(+), 651 deletions(-) diff --git a/ext/ota/ota3.test b/ext/ota/ota3.test index 8921c12b35..74dba1f166 100644 --- a/ext/ota/ota3.test +++ b/ext/ota/ota3.test @@ -63,19 +63,29 @@ do_execsql_test 2.0 { CREATE INDEX i1 ON x1(b, c); } {} -do_test 2.1 { - sqlite3 db2 ota.db - db2 eval { +foreach {tn otadb} { + 1 { CREATE TABLE data_x1(a, b, c, ota_control); INSERT INTO data_x1 VALUES(NULL, 'a', 'b', 0); } - db2 close - list [catch { run_ota test.db ota.db } msg] $msg -} {1 {SQLITE_MISMATCH - datatype mismatch}} -do_execsql_test 2.2 { - PRAGMA integrity_check; -} {ok} + 2 { + CREATE TABLE data_x1(c, b, a, ota_control); + INSERT INTO data_x1 VALUES('b', 'a', NULL, 0); + } +} { + do_test 2.$tn.1 { + forcedelete ota.db + sqlite3 db2 ota.db + db2 eval $otadb + db2 close + list [catch { run_ota test.db ota.db } msg] $msg + } {1 {SQLITE_MISMATCH - datatype mismatch}} + + do_execsql_test 2.1.2 { + PRAGMA integrity_check; + } {ok} +} #-------------------------------------------------------------------- # Test that missing columns are detected. @@ -102,4 +112,28 @@ do_execsql_test 2.2 { PRAGMA integrity_check; } {ok} +# Also extra columns. +# +do_execsql_test 2.3 { + CREATE TABLE x2(a INTEGER PRIMARY KEY, b, c); + CREATE INDEX i2 ON x2(b, c); +} {} + +do_test 2.4 { + forcedelete ota.db + sqlite3 db2 ota.db + db2 eval { + CREATE TABLE data_x2(a, b, c, d, ota_control); + INSERT INTO data_x2 VALUES(1, 'a', 2, 3, 0); + } + db2 close + breakpoint + list [catch { run_ota test.db ota.db } msg] $msg +} {1 SQLITE_ERROR} + +do_execsql_test 2.5 { + PRAGMA integrity_check; +} {ok} + finish_test + diff --git a/ext/ota/ota4.test b/ext/ota/ota4.test index b14225dc52..a12cbd8b7b 100644 --- a/ext/ota/ota4.test +++ b/ext/ota/ota4.test @@ -124,110 +124,5 @@ do_catchsql_test 1.5.4 { SELECT * FROM t1; } {1 {database is locked}} -#------------------------------------------------------------------------- -# These tests - ota4-2.* - aim to verify some properties of the ota_mode -# pragma. -# -# 1. Check that UNIQUE constraints are not tested in ota_mode. -# 2. Except for (real) PRIMARY KEY constraints. -# 3. Check that all non-temporary triggers are ignored. -# -reset_db -do_execsql_test 2.1.1 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); - CREATE UNIQUE INDEX i1 ON t1(b); - INSERT INTO t1 VALUES(1, 2, 3); - INSERT INTO t1 VALUES(2, 4, 6); -} - -do_execsql_test 2.1.2 { - PRAGMA ota_mode = 1; - INSERT INTO t1 VALUES(3, 2, 6); - UPDATE t1 SET b=2 WHERE a=2; - SELECT * FROM t1; -} { - 1 2 3 - 2 2 6 - 3 2 6 -} - -reset_db -do_execsql_test 2.2.1 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); - CREATE TABLE t2(x, y, z, PRIMARY KEY(y, z)) WITHOUT ROWID; - - INSERT INTO t1 VALUES(1, 2, 3); - INSERT INTO t2 VALUES(4, 5, 6); - PRAGMA ota_mode = 1; -} -do_catchsql_test 2.2.2 { - INSERT INTO t1 VALUES(1, 'two', 'three'); -} {1 {UNIQUE constraint failed: t1.a}} -do_catchsql_test 2.2.3 { - INSERT INTO t2 VALUES('four', 5, 6); -} {1 {UNIQUE constraint failed: t2.y, t2.z}} - -reset_db -do_execsql_test 2.3.1 { - CREATE TABLE t1(a, b, c); - CREATE TABLE log(x); - INSERT INTO t1 VALUES(1, 2, 3); - - CREATE TRIGGER tr1 BEFORE INSERT ON t1 BEGIN - INSERT INTO log VALUES('permanent'); - END; - CREATE TRIGGER tr2 AFTER INSERT ON t1 BEGIN - INSERT INTO log VALUES('permanent'); - END; - CREATE TRIGGER tr3 BEFORE DELETE ON t1 BEGIN - INSERT INTO log VALUES('permanent'); - END; - CREATE TRIGGER tr4 AFTER DELETE ON t1 BEGIN - INSERT INTO log VALUES('permanent'); - END; - CREATE TRIGGER tr5 BEFORE UPDATE ON t1 BEGIN - INSERT INTO log VALUES('permanent'); - END; - CREATE TRIGGER tr6 AFTER UPDATE ON t1 BEGIN - INSERT INTO log VALUES('permanent'); - END; - - CREATE TEMP TRIGGER ttr1 BEFORE INSERT ON t1 BEGIN - INSERT INTO log VALUES('temp'); - END; - CREATE TEMP TRIGGER ttr2 AFTER INSERT ON t1 BEGIN - INSERT INTO log VALUES('temp'); - END; - CREATE TEMP TRIGGER ttr3 BEFORE DELETE ON t1 BEGIN - INSERT INTO log VALUES('temp'); - END; - CREATE TEMP TRIGGER ttr4 AFTER DELETE ON t1 BEGIN - INSERT INTO log VALUES('temp'); - END; - CREATE TEMP TRIGGER ttr5 BEFORE UPDATE ON t1 BEGIN - INSERT INTO log VALUES('temp'); - END; - CREATE TEMP TRIGGER ttr6 AFTER UPDATE ON t1 BEGIN - INSERT INTO log VALUES('temp'); - END; -} -do_execsql_test 2.3.2 { - INSERT INTO t1 VALUES(4, 5, 6); - DELETE FROM t1 WHERE a = 4; - UPDATE t1 SET c = 6; - SELECT x FROM log; -} { - temp permanent temp permanent temp permanent - temp permanent temp permanent temp permanent -} -do_execsql_test 2.3.3 { - DELETE FROM log; - PRAGMA ota_mode = 1; - INSERT INTO t1 VALUES(4, 5, 6); - DELETE FROM t1 WHERE a = 4; - UPDATE t1 SET c = 6; - SELECT x FROM log; -} {temp temp temp temp temp temp} - finish_test diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c index 1727e51f1f..ae45db032b 100644 --- a/ext/ota/sqlite3ota.c +++ b/ext/ota/sqlite3ota.c @@ -102,8 +102,9 @@ struct OtaObjIter { sqlite3_stmt *pTblIter; /* Iterate through tables */ sqlite3_stmt *pIdxIter; /* Index iterator */ int nTblCol; /* Size of azTblCol[] array */ - char **azTblCol; /* Array of quoted column names */ + char **azTblCol; /* Array of unquoted column names */ char **azTblType; /* Array of column types */ + int *aiTblOrder; /* Order of columns in target table */ unsigned char *abTblPk; /* Array of flags - true for PK columns */ int eType; @@ -128,11 +129,18 @@ struct OtaObjIter { /* ** Values for OtaObjIter.eType +** +** 1: Table has an implicit rowid. +** 2: Table has an explicit IPK column. +** 3: Table has an external PK index. +** 4: Table is WITHOUT ROWID. +** 5: Table is a virtual table. */ -#define OTA_PK_REAL 1 /* Table has a real primary key */ -#define OTA_PK_EXTERNAL 2 /* Table has an external primary key index */ -#define OTA_PK_NONE 3 /* Table has no PK (use rowid) */ -#define OTA_PK_VTAB 4 /* Table is a virtual table (use rowid) */ +#define OTA_PK_NONE 1 +#define OTA_PK_IPK 2 +#define OTA_PK_EXTERNAL 3 +#define OTA_PK_WITHOUT_ROWID 4 +#define OTA_PK_VTAB 5 /* ** OTA handle. @@ -225,7 +233,7 @@ static int prepareFreeAndCollectError( /* ** Free the OtaObjIter.azTblCol[] and OtaObjIter.abTblPk[] arrays allocated -** by an earlier call to otaObjIterGetCols(). +** by an earlier call to otaObjIterCacheTableInfo(). */ static void otaObjIterFreeCols(OtaObjIter *pIter){ int i; @@ -236,6 +244,7 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){ sqlite3_free(pIter->azTblCol); pIter->azTblCol = 0; pIter->azTblType = 0; + pIter->aiTblOrder = 0; pIter->abTblPk = 0; pIter->nTblCol = 0; sqlite3_free(pIter->zMask); @@ -285,32 +294,44 @@ static int otaObjIterNext(sqlite3ota *p, OtaObjIter *pIter){ /* Free any SQLite statements used while processing the previous object */ otaObjIterClearStatements(pIter); + if( pIter->zIdx==0 ){ + rc = sqlite3_exec(p->db, + "DROP TRIGGER IF EXISTS temp.ota_insert_tr;" + "DROP TRIGGER IF EXISTS temp.ota_update1_tr;" + "DROP TRIGGER IF EXISTS temp.ota_update2_tr;" + "DROP TRIGGER IF EXISTS temp.ota_delete_tr;" + , 0, 0, &p->zErrmsg + ); + } - if( pIter->bCleanup ){ - otaObjIterFreeCols(pIter); - pIter->bCleanup = 0; - rc = sqlite3_step(pIter->pTblIter); - if( rc!=SQLITE_ROW ){ - rc = sqlite3_reset(pIter->pTblIter); - pIter->zTbl = 0; - }else{ - pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0); - rc = SQLITE_OK; - } - }else{ - if( pIter->zIdx==0 ){ - sqlite3_bind_text(pIter->pIdxIter, 1, pIter->zTbl, -1, SQLITE_STATIC); - } - rc = sqlite3_step(pIter->pIdxIter); - if( rc!=SQLITE_ROW ){ - rc = sqlite3_reset(pIter->pIdxIter); - pIter->bCleanup = 1; - pIter->zIdx = 0; + if( rc==SQLITE_OK ){ + if( pIter->bCleanup ){ + otaObjIterFreeCols(pIter); + pIter->bCleanup = 0; + rc = sqlite3_step(pIter->pTblIter); + if( rc!=SQLITE_ROW ){ + rc = sqlite3_reset(pIter->pTblIter); + pIter->zTbl = 0; + }else{ + pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0); + pIter->tnum = sqlite3_column_int(pIter->pTblIter, 1); + rc = SQLITE_OK; + } }else{ - pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0); - pIter->tnum = sqlite3_column_int(pIter->pIdxIter, 1); - pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2); - rc = SQLITE_OK; + if( pIter->zIdx==0 ){ + sqlite3_bind_text(pIter->pIdxIter, 1, pIter->zTbl, -1, SQLITE_STATIC); + } + rc = sqlite3_step(pIter->pIdxIter); + if( rc!=SQLITE_ROW ){ + rc = sqlite3_reset(pIter->pIdxIter); + pIter->bCleanup = 1; + pIter->zIdx = 0; + }else{ + pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0); + pIter->tnum = sqlite3_column_int(pIter->pIdxIter, 1); + pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2); + rc = SQLITE_OK; + } } } } @@ -336,8 +357,10 @@ static int otaObjIterFirst(sqlite3ota *p, OtaObjIter *pIter){ memset(pIter, 0, sizeof(OtaObjIter)); rc = prepareAndCollectError(p->db, &pIter->pTblIter, &p->zErrmsg, - "SELECT substr(name, 6) FROM ota.sqlite_master " - "WHERE type='table' AND name LIKE 'data_%'" + "SELECT substr(a.name, 6), b.rootpage FROM ota.sqlite_master AS a " + "LEFT JOIN main.sqlite_master AS b ON " + "(substr(a.name, 6)==b.name) " + "WHERE a.type='table' AND a.name LIKE 'data_%'" ); if( rc==SQLITE_OK ){ @@ -353,53 +376,6 @@ static int otaObjIterFirst(sqlite3ota *p, OtaObjIter *pIter){ return otaObjIterNext(p, pIter); } -/* -** Allocate a buffer and populate it with the double-quoted version of the -** string in the argument buffer, suitable for use as an SQL identifier. -** For example: -** -** [quick `brown` fox] -> [`quick ``brown`` fox`] -** -** Assuming the allocation is successful, a pointer to the new buffer is -** returned. It is the responsibility of the caller to free it using -** sqlite3_free() at some point in the future. Or, if the allocation fails, -** a NULL pointer is returned. -*/ -static char *otaQuoteName(const char *zName){ - int nName = strlen(zName); - char *zRet = sqlite3_malloc(nName * 2 + 2 + 1); - if( zRet ){ - int i; - char *p = zRet; - *p++ = '`'; - for(i=0; irc==SQLITE_OK ); @@ -441,7 +417,8 @@ static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){ memset(azNew, 0, nByte); pIter->azTblCol = azNew; pIter->azTblType = &azNew[nCol]; - pIter->abTblPk = (unsigned char*)&pIter->azTblType[nCol]; + pIter->aiTblOrder = (int*)&pIter->azTblType[nCol]; + pIter->abTblPk = (unsigned char*)&pIter->aiTblOrder[nCol]; }else{ p->rc = SQLITE_NOMEM; } @@ -466,50 +443,33 @@ static char *otaStrndup(const char *zStr, int nStr, int *pRc){ } -/* -** Return true if zTab is the name of a virtual table within the target -** database. -*/ -static int otaIsVtab(sqlite3ota *p, const char *zTab){ - int res = 0; - sqlite3_stmt *pSelect = 0; - - if( p->rc==SQLITE_OK ){ - p->rc = prepareAndCollectError(p->db, &pSelect, &p->zErrmsg, - "SELECT count(*) FROM sqlite_master WHERE name = ? AND type='table' " - "AND sql LIKE 'CREATE VIRTUAL TABLE%'" - ); - } - - if( p->rc==SQLITE_OK ){ - sqlite3_bind_text(pSelect, 1, zTab, -1, SQLITE_STATIC); - if( sqlite3_step(pSelect)==SQLITE_ROW ){ - res = sqlite3_column_int(pSelect, 0); - } - p->rc = sqlite3_finalize(pSelect); - } - - return res; -} - /* ** If they are not already populated, populate the pIter->azTblCol[], ** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to -** the table that the iterator currently points to. +** the table (not index) 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 ** the OTA handle. */ -static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ +static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){ if( pIter->azTblCol==0 ){ sqlite3_stmt *pStmt = 0; int nCol = 0; int i; /* for() loop iterator variable */ int rc2; /* sqlite3_finalize() return value */ int bOtaRowid = 0; /* If input table has column "ota_rowid" */ + int iOrder = 0; + /* Figure out the type of table this step will deal with. */ assert( pIter->eType==0 ); + sqlite3_test_control( + SQLITE_TESTCTRL_TBLTYPE, p->db, "main", pIter->zTbl, &pIter->eType + ); + assert( pIter->eType==OTA_PK_NONE || pIter->eType==OTA_PK_IPK + || pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_WITHOUT_ROWID + || pIter->eType==OTA_PK_VTAB + ); /* Populate the azTblCol[] and nTblCol variables based on the columns ** of the input table. Ignore any input table columns that begin with @@ -524,9 +484,8 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ for(i=0; p->rc==SQLITE_OK && irc); pIter->azTblCol[pIter->nTblCol++] = zCopy; - if( zCopy==0 ) p->rc = SQLITE_NOMEM; } else if( 0==sqlite3_stricmp("ota_rowid", zName) ){ bOtaRowid = 1; @@ -535,9 +494,19 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ sqlite3_finalize(pStmt); pStmt = 0; + if( p->rc==SQLITE_OK + && bOtaRowid!=(pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE) + ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf( + "table data_%q %s ota_rowid column", pIter->zTbl, + (bOtaRowid ? "may not have" : "requires") + ); + } + /* Check that all non-HIDDEN columns in the destination table are also - ** present in the input table. Populate the abTblPk[] array at the - ** same time. */ + ** present in the input table. Populate the abTblPk[], azTblType[] and + ** aiTblOrder[] arrays at the same time. */ if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->db, &pStmt, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.table_info(%Q)", pIter->zTbl) @@ -546,7 +515,7 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zName = (const char*)sqlite3_column_text(pStmt, 1); for(i=0; inTblCol; i++){ - if( otaMatchName(zName, pIter->azTblCol[i]) ) break; + if( 0==strcmp(zName, pIter->azTblCol[i]) ) break; } if( i==pIter->nTblCol ){ p->rc = SQLITE_ERROR; @@ -556,37 +525,34 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ }else{ int iPk = sqlite3_column_int(pStmt, 5); const char *zType = (const char*)sqlite3_column_text(pStmt, 2); + pIter->aiTblOrder[i] = iOrder++; pIter->azTblType[i] = otaStrndup(zType, -1, &p->rc); pIter->abTblPk[i] = (iPk!=0); - if( iPk ){ - pIter->eType = (iPk<0) ? OTA_PK_EXTERNAL : OTA_PK_REAL; - } } } - rc2 = sqlite3_finalize(pStmt); - if( p->rc==SQLITE_OK ) p->rc = rc2; - - if( p->rc==SQLITE_OK ){ - if( pIter->eType==0 ){ - /* This must either be a virtual table, or a regular table with no - ** PRIMARY KEY declaration whatsoever. */ - if( bOtaRowid==0 ){ - p->rc = SQLITE_ERROR; - p->zErrmsg = sqlite3_mprintf( - "table data_%q requires ota_rowid column", pIter->zTbl - ); - }else if( otaIsVtab(p, pIter->zTbl) ){ - pIter->eType = OTA_PK_VTAB; - }else{ - pIter->eType = OTA_PK_NONE; + while( iOrdernTblCol ){ + for(i=0; inTblCol; i++){ + if( pIter->aiTblOrder[i]==0 ){ + pIter->aiTblOrder[i] = iOrder++; + continue; } - }else if( bOtaRowid ){ - p->rc = SQLITE_ERROR; - p->zErrmsg = sqlite3_mprintf( - "table data_%q may not have ota_rowid column", pIter->zTbl - ); } } + + /* Check that there were no extra columns in the data_xxx table that + ** are not present in the target table. If there are, an error. */ +#if 0 + assert( iOrder<=pIter->nTblCol ); + if( p->rc==SQLITE_OK && iOrder!=pIter->nTblCol ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("data_%q has %d columns, expected %d", + pIter->zTbl, iOrder, pIter->nTblCol + ); + } +#endif + + rc2 = sqlite3_finalize(pStmt); + if( p->rc==SQLITE_OK ) p->rc = rc2; } return p->rc; @@ -612,60 +578,18 @@ static char *otaMPrintfAndCollectError(sqlite3ota *p, const char *zFmt, ...){ ** This function constructs and returns a pointer to a nul-terminated ** string containing some SQL clause or list based on one or more of the ** column names currently stored in the pIter->azTblCol[] array. -** -** If an OOM error is encountered, NULL is returned and an error code -** left in the OTA handle passed as the first argument. Otherwise, a pointer -** to the allocated string buffer is returned. It is the responsibility -** of the caller to eventually free this buffer using sqlite3_free(). -** -** The number of column names to include in the returned string is passed -** as the third argument. -** -** If arguments aiCol and azCollate are both NULL, then the returned string -** contains the first nCol column names as a comma-separated list. For -** example: -** -** "a", "b", "c" -** -** If argument aiCol is not NULL, it must point to an array containing nCol -** entries - the index of each column name to include in the comma-separated -** list. For example, if aiCol[] contains {2, 0, 1), then the returned -** string is changed to: -** -** "c", "a", "b" -** -** If azCollate is not NULL, it must also point to an array containing nCol -** entries - collation sequence names to associated with each element of -** the comma separated list. For example, ef azCollate[] contains -** {"BINARY", "NOCASE", "REVERSE"}, then the retuned string is: -** -** "c" COLLATE "BINARY", "a" COLLATE "NOCASE", "b" COLLATE "REVERSE" -** */ static char *otaObjIterGetCollist( sqlite3ota *p, /* OTA object */ - OtaObjIter *pIter, /* Object iterator for column names */ - int nCol, /* Number of column names */ - int *aiCol, /* Array of nCol column indexes */ - const char **azCollate /* Array of nCol collation sequence names */ + OtaObjIter *pIter /* Object iterator for column names */ ){ char *zList = 0; - if( p->rc==SQLITE_OK ){ - const char *zSep = ""; - int i; - for(i=0; i=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]); - } - zSep = ", "; - if( zList==0 ){ - p->rc = SQLITE_NOMEM; - break; - } - } + const char *zSep = ""; + int i; + for(i=0; inTblCol; i++){ + const char *z = pIter->azTblCol[i]; + zList = otaMPrintfAndCollectError(p, "%z%s\"%w\"", zList, zSep, z); + zSep = ", "; } return zList; } @@ -709,7 +633,7 @@ static char *otaObjIterGetIndexCols( char *zImpPK = 0; /* String to return via *pzImposterPK */ char *zWhere = 0; /* String to return via *pzWhere */ int nBind = 0; /* Value to return via *pnBind */ - const char *zComma = ""; /* Set to ", " later on */ + const char *zCom = ""; /* Set to ", " later on */ const char *zAnd = ""; /* Set to " AND " later on */ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = ? */ @@ -729,7 +653,7 @@ static char *otaObjIterGetIndexCols( if( iCid<0 ){ /* An integer primary key. If the table has an explicit IPK, use ** its name. Otherwise, use "ota_rowid". */ - if( pIter->eType==OTA_PK_REAL ){ + if( pIter->eType==OTA_PK_IPK ){ int i; for(i=0; inTblCol && pIter->abTblPk[i]==0; i++); assert( inTblCol ); @@ -743,16 +667,16 @@ static char *otaObjIterGetIndexCols( zType = pIter->azTblType[iCid]; } - zRet = sqlite3_mprintf("%z%s%s COLLATE %Q", zRet, zComma, zCol, zCollate); + zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom, zCol, zCollate); if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){ - zImpPK = sqlite3_mprintf("%z%sc%d", zImpPK, zComma, nBind); + zImpPK = sqlite3_mprintf("%z%sc%d", zImpPK, zCom, nBind); } zImpCols = sqlite3_mprintf( - "%z%sc%d %s COLLATE %Q", zImpCols, zComma, nBind, zType, zCollate + "%z%sc%d %s COLLATE %Q", zImpCols, zCom, nBind, zType, zCollate ); zWhere = sqlite3_mprintf("%z%sc%d IS ?", zWhere, zAnd, nBind); if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM; - zComma = ", "; + zCom = ", "; zAnd = " AND "; nBind++; } @@ -800,7 +724,8 @@ static char *otaObjIterGetOldlist( const char *zS = ""; int i; for(i=0; inTblCol; i++){ - zList = sqlite3_mprintf("%z%s%s.%s", zList, zS, zObj, pIter->azTblCol[i]); + const char *zCol = pIter->azTblCol[i]; + zList = sqlite3_mprintf("%z%s%s.\"%w\"", zList, zS, zObj, zCol); zS = ", "; if( zList==0 ){ p->rc = SQLITE_NOMEM; @@ -831,20 +756,18 @@ static char *otaObjIterGetWhere( OtaObjIter *pIter ){ char *zList = 0; - if( p->rc==SQLITE_OK ){ - if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){ - zList = otaMPrintfAndCollectError(p, "_rowid_ = ?%d", pIter->nTblCol+1); - }else{ - const char *zSep = ""; - int i; - for(i=0; inTblCol; i++){ - if( pIter->abTblPk[i] ){ - const char *zCol = pIter->azTblCol[i]; - zList = otaMPrintfAndCollectError( - p, "%z%s%s=?%d", zList, zSep, zCol, i+1 - ); - zSep = " AND "; - } + if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){ + zList = otaMPrintfAndCollectError(p, "_rowid_ = ?%d", pIter->nTblCol+1); + }else{ + const char *zSep = ""; + int i; + for(i=0; inTblCol; i++){ + if( pIter->abTblPk[i] ){ + const char *zCol = pIter->azTblCol[i]; + zList = otaMPrintfAndCollectError( + p, "%z%s\"%w\"=?%d", zList, zSep, zCol, i+1 + ); + zSep = " AND "; } } } @@ -880,13 +803,14 @@ static char *otaObjIterGetSetlist( for(i=0; inTblCol; i++){ char c = zMask[i]; if( c=='x' ){ - zList = otaMPrintfAndCollectError(p, "%z%s%s=?%d", + zList = otaMPrintfAndCollectError(p, "%z%s\"%w\"=?%d", zList, zSep, pIter->azTblCol[i], i+1 ); zSep = ", "; } if( c=='d' ){ - zList = otaMPrintfAndCollectError(p, "%z%s%s=ota_delta(%s, ?%d)", + zList = otaMPrintfAndCollectError(p, + "%z%s\"%w\"=ota_delta(\"%w\", ?%d)", zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 ); zSep = ", "; @@ -915,6 +839,81 @@ static char *otaObjIterGetBindlist(sqlite3ota *p, int nBind){ return zRet; } +/* +** If an error has already occurred when this function is called, it +** immediately returns zero (without doing any work). Or, if an error +** occurs during the execution of this function, it sets the error code +** in the sqlite3ota object indicated by the first argument and returns +** zero. +** +** The iterator passed as the second argument is guaranteed to point to +** a table (not an index) when this function is called. This function +** attempts to create any imposter tables required to write to the main +** table b-tree of the table before returning. Non-zero is returned if +** imposter tables are created, or zero otherwise. +** +** The required imposter tables depend on the type of table that the +** iterator currently points to. +** +** OTA_PK_NONE, OTA_PK_IPK, OTA_PK_WITHOUT_ROWID: +** A single imposter table is required. With the same schema as +** the actual target table (less any UNIQUE constraints). More +** precisely, the "same schema" means the same columns, types, collation +** sequences and primary key declaration. +** +** OTA_PK_VTAB: +** No imposters required. +** +** OTA_PK_EXTERNAL: +** Two imposters are required (TODO!!) +*/ +static void otaCreateImposterTable(sqlite3ota *p, OtaObjIter *pIter){ + if( p->rc==SQLITE_OK && pIter->eType!=OTA_PK_VTAB ){ + int tnum = pIter->tnum; + const char *zComma = ""; + char *zSql = 0; + int iCol; + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1); + + for(iCol=0; p->rc==SQLITE_OK && iColnTblCol; iCol++){ + int iDataCol = pIter->aiTblOrder[iCol]; + const char *zCol = pIter->azTblCol[iDataCol]; + const char *zColl = 0; + p->rc = sqlite3_table_column_metadata( + p->db, "main", pIter->zTbl, zCol, 0, &zColl, 0, 0, 0 + ); + zSql = otaMPrintfAndCollectError(p, "%z%s\"%w\" %s COLLATE %s", + zSql, zComma, zCol, pIter->azTblType[iDataCol], zColl + ); + zComma = ", "; + } + + if( pIter->eType==OTA_PK_IPK || pIter->eType==OTA_PK_WITHOUT_ROWID ){ + zSql = otaMPrintfAndCollectError(p, "%z, PRIMARY KEY(", zSql); + zComma = ""; + for(iCol=0; iColnTblCol; iCol++){ + if( pIter->abTblPk[iCol] ){ + zSql = otaMPrintfAndCollectError(p, "%z%s\"%w\"", + zSql, zComma, pIter->azTblCol[iCol] + ); + zComma = ", "; + } + } + zSql = otaMPrintfAndCollectError(p, "%z)", zSql); + } + + zSql = otaMPrintfAndCollectError(p, "CREATE TABLE ota_imposter(%z)%s", + zSql, (pIter->eType==OTA_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "") + ); + if( p->rc==SQLITE_OK ){ + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum); + p->rc = sqlite3_exec(p->db, zSql, 0, 0, &p->zErrmsg); + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); + } + sqlite3_free(zSql); + } +} + /* ** Ensure that the SQLite statement handles required to update the ** target database object currently indicated by the iterator passed @@ -926,7 +925,7 @@ static int otaObjIterPrepareAll( int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */ ){ assert( pIter->bCleanup==0 ); - if( pIter->pSelect==0 && otaObjIterGetCols(p, pIter)==SQLITE_OK ){ + if( pIter->pSelect==0 && otaObjIterCacheTableInfo(p, pIter)==SQLITE_OK ){ const int tnum = pIter->tnum; char *zCollist = 0; /* List of indexed columns */ char **pz = &p->zErrmsg; @@ -939,9 +938,9 @@ static int otaObjIterPrepareAll( } if( zIdx ){ - char *zImposterCols = 0; - char *zImposterPK = 0; - char *zWhere = 0; + char *zImposterCols = 0; /* Columns for imposter table */ + char *zImposterPK = 0; /* Primary key declaration for imposter */ + char *zWhere = 0; /* WHERE clause on PK columns */ char *zBind = 0; int nBind = 0; @@ -1005,13 +1004,15 @@ static int otaObjIterPrepareAll( sqlite3_free(zBind); }else{ int bOtaRowid = (pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE); - const char *zTbl = pIter->zTbl; + const char *zTbl = pIter->zTbl; /* Table this step applies to */ + const char *zWrite; /* Imposter table name */ + + char *zBindings = otaObjIterGetBindlist(p, pIter->nTblCol + bOtaRowid); char *zWhere = otaObjIterGetWhere(p, pIter); char *zOldlist = otaObjIterGetOldlist(p, pIter, "old"); char *zNewlist = otaObjIterGetOldlist(p, pIter, "new"); - char *zBindings = otaObjIterGetBindlist(p, pIter->nTblCol + bOtaRowid); - zCollist = otaObjIterGetCollist(p, pIter, pIter->nTblCol, 0, 0); + zCollist = otaObjIterGetCollist(p, pIter); pIter->nCol = pIter->nTblCol; /* Create the SELECT statement to read keys from data_xxx */ @@ -1024,12 +1025,16 @@ static int otaObjIterPrepareAll( ); } + /* Create the imposter table or tables (if required). */ + otaCreateImposterTable(p, pIter); + zWrite = (pIter->eType==OTA_PK_VTAB ? zTbl : "ota_imposter"); + /* Create the INSERT statement to write to the target PK b-tree */ if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->db, &pIter->pInsert, pz, sqlite3_mprintf( "INSERT INTO main.%Q(%s%s) VALUES(%s)", - zTbl, zCollist, (bOtaRowid ? ", _rowid_" : ""), zBindings + zWrite, zCollist, (bOtaRowid ? ", _rowid_" : ""), zBindings ) ); } @@ -1038,7 +1043,7 @@ static int otaObjIterPrepareAll( if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->db, &pIter->pDelete, pz, sqlite3_mprintf( - "DELETE FROM main.%Q WHERE %s", zTbl, zWhere + "DELETE FROM main.%Q WHERE %s", zWrite, zWhere ) ); } @@ -1055,34 +1060,34 @@ static int otaObjIterPrepareAll( "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 " + "CREATE TEMP TRIGGER ota_delete_tr BEFORE DELETE ON ota_imposter " "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 " + "CREATE TEMP TRIGGER ota_update1_tr BEFORE UPDATE ON ota_imposter " "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 " + "CREATE TEMP TRIGGER ota_update2_tr AFTER UPDATE ON ota_imposter " "BEGIN " " INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(3, %s);" "END;" , zTbl, (pIter->eType==OTA_PK_EXTERNAL ? ", 0 AS ota_rowid" : "") , zTbl, - zTbl, zTbl, zTbl, zCollist, zOtaRowid, zOldlist, - zTbl, zTbl, zTbl, zCollist, zOtaRowid, zOldlist, - zTbl, zTbl, zTbl, zCollist, zOtaRowid, zNewlist + zTbl, zCollist, zOtaRowid, zOldlist, + zTbl, zCollist, zOtaRowid, zOldlist, + zTbl, zCollist, zOtaRowid, zNewlist ); if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){ otaMPrintfExec(p, - "CREATE TEMP TRIGGER ota_insert_%q AFTER INSERT ON main.%Q " + "CREATE TEMP TRIGGER ota_insert_tr AFTER INSERT ON ota_imposter " "BEGIN " " INSERT INTO 'ota_tmp_%q'(ota_control, %s, ota_rowid)" " VALUES(0, %s);" "END;" - , zTbl, zTbl, zTbl, zCollist, zNewlist + , zTbl, zCollist, zNewlist ); } }else if( p->rc==SQLITE_OK ){ @@ -1133,8 +1138,9 @@ static int otaGetUpdateStmt( 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 + zUpdate = sqlite3_mprintf("UPDATE \"%w\" SET %s WHERE %s", + (pIter->eType==OTA_PK_VTAB ? pIter->zTbl : "ota_imposter"), + zSet, zWhere ); p->rc = prepareFreeAndCollectError( p->db, &pIter->pUpdate, &p->zErrmsg, zUpdate @@ -1337,9 +1343,22 @@ static int otaStep(sqlite3ota *p){ } for(i=0; inCol; i++){ + /* If this is an INSERT into a table b-tree and the table has an + ** explicit INTEGER PRIMARY KEY, check that this is not an attempt + ** to write a NULL into the IPK column. That is not permitted. */ + if( eType==OTA_INSERT + && pIter->zIdx==0 && pIter->eType==OTA_PK_IPK && pIter->abTblPk[i] + && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL + ){ + p->rc = SQLITE_MISMATCH; + p->zErrmsg = sqlite3_mprintf("datatype mismatch"); + goto step_out; + } + if( eType==SQLITE_DELETE && pIter->zIdx==0 && pIter->abTblPk[i]==0 ){ continue; } + pVal = sqlite3_column_value(pIter->pSelect, i); sqlite3_bind_value(pWriter, i+1, pVal); } @@ -1383,6 +1402,7 @@ static int otaStep(sqlite3ota *p){ } } + step_out: return p->rc; } diff --git a/manifest b/manifest index 3c7bd57c80..0a49c2b2a1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\sota\suse\simposter\stables\sto\swrite\sto\sindexes\sinstead\sof\sthe\ssqlite3_index_writer()\sinterface.\sThe\serror\shandling\sin\sthis\sversion\sis\sbroken\sin\sa\sfew\ssmall\sways. -D 2015-01-31T20:42:04.027 +C Remove\s"PRAGMA\sota_mode". +D 2015-02-03T15:56:08.271 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -128,15 +128,15 @@ F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91 F ext/ota/ota1.test d76b9ec77437759e9da0ff4abe9c070bb9f4eae1 F ext/ota/ota10.test ab815dff9cef7248c504f06b888627d236f25e9c F ext/ota/ota2.test 2829bc08ffbb71b605392a68fedfd554763356a7 -F ext/ota/ota3.test 71bd8cc0cf8d7e7d9bb11a1fcc238320a5a9d8c8 -F ext/ota/ota4.test 60f897f329a6782ef2f24862640acf3c52e48077 +F ext/ota/ota3.test a77efbce7723332eb688d2b28bf18204fc9614d7 +F ext/ota/ota4.test 82434aa39c9acca6cd6317f6b0ab07b0ec6c2e7d F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb F ext/ota/ota6.test 82f1f757ec9b2ad07d6de4060b8e3ba8e44dfdd3 F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b F ext/ota/otafault.test 508ba87c83d632670ac0f94371a465d4bb4d49dd -F ext/ota/sqlite3ota.c 975ccfe032ee81ee39368ed5e9cb33cbb6edc603 +F ext/ota/sqlite3ota.c 52c91eec41b8fbb5ed12a8f0a2159bc5ec16498f F ext/ota/sqlite3ota.h ce378c0c503f625611713133f9c79704ea4ee7a4 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f @@ -188,7 +188,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c ddca0ae681c49813a4bfd88d5f922fac71e0ffaa +F src/btree.c 2a1245df0356a229bcd0fd87a8536b5067f16e82 F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474 F src/btreeInt.h a3d0ae1d511365e1a2b76ad10960dbe55c286f34 F src/build.c eefaa4f1d86bc3c08023a61fdd1e695b47796975 @@ -196,7 +196,7 @@ F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463 F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887 F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac -F src/delete.c e68b70ac41dcf6e92a813d860fa984fcd9aec042 +F src/delete.c bd1a91ddd247ce13004075251e0b7fe2bf9925ef F src/expr.c abe930897ccafae3819fd2855cbc1b00c262fd12 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12 @@ -205,12 +205,12 @@ F src/global.c 12561d70a1b25f67b21154622bb1723426724f75 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c fef86ab8218cf0d926db93280b9eb5b583981353 +F src/insert.c 5b9243a33726008cc4132897d2be371db12a13be F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 -F src/main.c c4cb192ebf0bcc975648ae05ac40bc1f40018c52 +F src/main.c 55d548a2c2f32d27366968c394d091475f7ea00a F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987 @@ -238,7 +238,7 @@ F src/parse.y c5d0d964f9ac023e8154cad512e54b0b6058e086 F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf -F src/pragma.c e49831e54c72894cce08702fe2e127e5c53d90f0 +F src/pragma.c 26fc55619109828c9b7add4cfa8a961b6f4c456d F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 F src/printf.c 05edc41450d0eb2c05ef7db113bf32742ae65325 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 @@ -246,15 +246,15 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 1f2087523007c42900ffcbdeaef06a23ad9329fc F src/shell.c 22b4406b0b59efd14b3b351a5809dda517df6d30 -F src/sqlite.h.in 78e493f94202d8083dd270e257786a6311d1fb3b +F src/sqlite.h.in 8913937ba11415bf369818431700adf3a921fb18 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 66180aa8f81155a7f391bbf759ee5a3b61d2f89f +F src/sqliteInt.h 57f8f45028598cc2877fc08ac03b402242242c68 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c e7a09215315a978057fb42c640f890160dbcc45e F src/tclsqlite.c b321464aba1fff1ed9317ebc82a1a94887f97af8 -F src/test1.c 313567541c980e45220d6faed393b6ad454f8ecd +F src/test1.c ce8ea168800d129acb2c0afdf2831ddf8667e082 F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622 F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e @@ -302,7 +302,7 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 F src/tokenize.c e00458c9938072b0ea711c850b8dcf4ddcb5fe18 -F src/trigger.c 6dcdf46a21acf4d4e011c809b2c971e63f797a1a +F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e @@ -312,7 +312,7 @@ F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71 F src/vdbeaux.c 97911edb61074b871ec4aa2d6bb779071643dee5 -F src/vdbeblob.c ad7787440295e43c12248dc48cde4b13e5df4ca0 +F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 @@ -1218,7 +1218,7 @@ F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl 5a401a3f5461fedb2e3230eb9908a18d485fefea +F tool/mkpragmatab.tcl aea392b69f8e72715760629cd50411d37bc85de4 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 9ef48e1748dce7b844f67e2450ff9dfeb0fb4ab5 F tool/mksqlite3c.tcl cfde806851c413db7689b9cb74a4eeb92539c601 @@ -1254,7 +1254,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 f9b6dc77021ee421bffd5697d5d337d3bbd07eb9 -R 907483269529ba471a525b7f8d05bc2e +P cdaeab467f6aa3217be161377a9b78a4eec37093 +R 2703aba199c695992db82956950982ca U dan -Z 87f206a3330dd276f74650f9e68af8ed +Z fae9dc4e5e5c1a2d2a162b422a05ccf9 diff --git a/manifest.uuid b/manifest.uuid index ecf8a3c6bb..0e07d68cdf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cdaeab467f6aa3217be161377a9b78a4eec37093 \ No newline at end of file +1c111447a07687c30ed4ad5a6c27a169c85b7ea6 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 4f752066ac..eb5151351c 100644 --- a/src/btree.c +++ b/src/btree.c @@ -151,8 +151,7 @@ static int hasSharedCacheTableLock( ** and has the read-uncommitted flag set, then no lock is required. ** Return true immediately. */ - if( (pBtree->db->flags & SQLITE_OtaMode) - || (pBtree->sharable==0) + if( (pBtree->sharable==0) || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) ){ return 1; diff --git a/src/delete.c b/src/delete.c index 17f7a87459..011fb80dee 100644 --- a/src/delete.c +++ b/src/delete.c @@ -730,9 +730,6 @@ void sqlite3GenerateRowIndexDelete( Vdbe *v; /* The prepared statement under construction */ Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */ - /* Skip this if we are in OTA mode */ - if( pParse->db->flags & SQLITE_OtaMode ) return; - v = pParse->pVdbe; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ diff --git a/src/insert.c b/src/insert.c index 0cc2078179..a5c3f3e92d 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1365,10 +1365,6 @@ void sqlite3GenerateConstraintChecks( int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ - /* If the "ota_mode" flag is set, ignore all indexes except the PK - ** index of WITHOUT ROWID tables. */ - if( (db->flags & SQLITE_OtaMode) && pIdx!=pPk) continue; - if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ if( bAffinityDone==0 ){ sqlite3TableAffinity(v, pTab, regNewData+1); @@ -1560,15 +1556,6 @@ void sqlite3CompleteInsertion( assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( aRegIdx[i]==0 ) continue; - - /* If the "ota_mode" flag is set, ignore all indexes except the PK - ** index of WITHOUT ROWID tables. */ - if( (pParse->db->flags & SQLITE_OtaMode) - && (HasRowid(pTab) || pIdx->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) - ){ - continue; - } - bAffinityDone = 1; if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); diff --git a/src/main.c b/src/main.c index 7bca1e5777..710d1dfb84 100644 --- a/src/main.c +++ b/src/main.c @@ -3654,6 +3654,45 @@ int sqlite3_test_control(int op, ...){ sqlite3_mutex_leave(db->mutex); break; } + + /* sqlite3_test_control(SQLITE_TESTCTRL_TBLTYPE, db, dbName, zTbl, peType) + ** + ** peType is of type (int*), a pointer to an output parameter of type + ** (int). This call sets the output parameter as follows, depending + ** on the type of the table specified by parameters dbName and zTbl. + ** + ** 0: No such table. + ** 1: Table has an implicit rowid. + ** 2: Table has an explicit IPK column. + ** 3: Table has an external PK index. + ** 4: Table is WITHOUT ROWID. + ** 5: Table is a virtual table. + */ + case SQLITE_TESTCTRL_TBLTYPE: { + sqlite3 *db = va_arg(ap, sqlite3*); + const char *zDb = va_arg(ap, const char*); + const char *zTab = va_arg(ap, const char*); + int *peType = va_arg(ap, int*); + Table *pTab; + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + pTab = sqlite3FindTable(db, zTab, zDb); + if( pTab==0 ){ + *peType = 0; + }else if( IsVirtual(pTab) ){ + *peType = 5; + }else if( HasRowid(pTab)==0 ){ + *peType = 4; + }else if( pTab->iPKey>=0 ){ + *peType = 2; + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + *peType = (pPk ? 3 : 1); + } + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + break; + } } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ diff --git a/src/pragma.c b/src/pragma.c index a2913abdbd..61c721f4d2 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -320,14 +320,6 @@ static const struct sPragmaNames { /* ePragTyp: */ PragTyp_MMAP_SIZE, /* ePragFlag: */ 0, /* iArg: */ 0 }, -#endif -#if defined(SQLITE_ENABLE_OTA) - { /* zName: */ "ota_mode", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_OtaMode }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) { /* zName: */ "page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragFlag: */ PragFlag_NeedSchema, @@ -496,7 +488,7 @@ static const struct sPragmaNames { /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; -/* Number of pragmas: 59 on by default, 74 total. */ +/* Number of pragmas: 59 on by default, 73 total. */ /* End of the automatically generated pragma table. ***************************************************************************/ @@ -1545,9 +1537,6 @@ void sqlite3Pragma( k = 1; }else{ for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} - if( (db->flags & SQLITE_OtaMode) && HasRowid(pTab) ){ - k = -1 * k; - } } sqlite3VdbeAddOp2(v, OP_Integer, k, 6); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 6e02a98688..1cba5b1772 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6266,7 +6266,8 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 -#define SQLITE_TESTCTRL_LAST 25 +#define SQLITE_TESTCTRL_TBLTYPE 26 +#define SQLITE_TESTCTRL_LAST 26 /* ** CAPI3REF: SQLite Runtime Status @@ -7585,66 +7586,6 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( */ SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); -/* -** Allocate a statement handle that may be used to write directly to an -** index b-tree. This allows the user to create a corrupt database. Once -** the statement handle is allocated, it may be used with the same APIs -** as any statement handle created with sqlite3_prepare(). -** -** The statement writes to the index specified by parameter zIndex, which -** must be in the "main" database. If argument bDelete is false, then each -** time the statement is sqlite3_step()ed, an entry is inserted into the -** b-tree index. If it is true, then an entry may be deleted (or may not, if -** the specified key is not found) each time the statement is -** sqlite3_step()ed. -** -** If statement compilation is successful, *ppStmt is set to point to the -** new statement handle and SQLITE_OK is returned. Otherwise, if an error -** occurs, *ppStmt is set to NULL and an error code returned. An error -** message may be left in the database handle in this case. -** -** If statement compilation succeeds, output variable *pnCol is set to the -** total number of columns in the index, including the primary key columns -** at the end. Variable *paiCol is set to point to an array *pnCol entries -** in size. Each entry is the table column index, numbered from zero from left -** to right, of the corresponding index column. For example, if: -** -** CREATE TABLE t1(a, b, c, d); -** CREATE INDEX i1 ON t1(b, c); -** -** then *pnCol is 3 and *paiCol points to an array containing {1, 2, -1}. -** If table t1 had an explicit INTEGER PRIMARY KEY, then the "-1" in the -** *paiCol array would be replaced by its column index. Or if: -** -** CREATE TABLE t2(a, b, c, d, PRIMARY KEY(d, c)) WITHOUT ROWID; -** CREATE INDEX i2 ON t2(a); -** -** then (*pnCol) is 3 and *paiCol points to an array containing {0, 3, 2}. -** -** The lifetime of the array is the same as that of the statement handle - -** it is automatically freed when the statement handle is passed to -** sqlite3_finalize(). -** -** The statement has (*pnCol) SQL variables that values may be bound to. -** They correspond to the values used to create the index key that is -** inserted or deleted when the statement is stepped. -** -** If the index is a UNIQUE index, the usual checking and error codes apply -** to insert operations. -** -** This API is only available if SQLITE_ENABLE_OTA is defined at compile -** time. It is intended for use by the OTA extension only. As such, it is -** subject to change or removal at any point. -*/ -int sqlite3_index_writer( - sqlite3 *db, - int bDelete, /* Zero for insert, non-zero for delete */ - const char *zIndex, /* Index to write to */ - sqlite3_stmt**, /* OUT: New statement handle */ - const char ***pazColl, /* OUT: Collation sequence for each column */ - int **paiCol, int *pnCol /* OUT: See above */ -); - /* ** Incremental checkpoint API. ** diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 9de37160bf..5fdbc6d65d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1207,12 +1207,6 @@ struct sqlite3 { #define SQLITE_QueryOnly 0x02000000 /* Disable database changes */ #define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */ -#ifdef SQLITE_ENABLE_OTA -# define SQLITE_OtaMode 0x08000000 /* True in "ota mode" */ -#else -# define SQLITE_OtaMode 0x00000000 -#endif - /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to diff --git a/src/test1.c b/src/test1.c index ae6e7bc0ea..d3c3d314bf 100644 --- a/src/test1.c +++ b/src/test1.c @@ -6922,11 +6922,11 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_user_change", test_user_change, 0 }, { "sqlite3_user_delete", test_user_delete, 0 }, #endif - #ifdef SQLITE_ENABLE_STMT_SCANSTATUS { "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 }, { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 }, #endif + }; static int bitmask_size = sizeof(Bitmask)*8; diff --git a/src/trigger.c b/src/trigger.c index 44b9b89fcc..d2e7b5a1e6 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -43,14 +43,10 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){ ** To state it another way: This routine returns a list of all triggers ** that fire off of pTab. The list will include any TEMP triggers on ** pTab as well as the triggers lised in pTab->pTrigger. -** -** If the SQLITE_OtaMode flag is set, do not include any non-temporary -** triggers in the returned list. */ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema * const pTmpSchema = pParse->db->aDb[1].pSchema; Trigger *pList = 0; /* List of triggers to return */ - const int bOta = !!(pParse->db->flags & SQLITE_OtaMode); if( pParse->disableTriggers ){ return 0; @@ -64,13 +60,13 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ if( pTrig->pTabSchema==pTab->pSchema && 0==sqlite3StrICmp(pTrig->table, pTab->zName) ){ - pTrig->pNext = ((pList || bOta) ? pList : pTab->pTrigger); + pTrig->pNext = (pList ? pList : pTab->pTrigger); pList = pTrig; } } } - return ((pList || bOta) ? pList : pTab->pTrigger); + return (pList ? pList : pTab->pTrigger); } /* diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 93a17ed384..cf1eb59054 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -467,183 +467,4 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ return rc; } -#ifdef SQLITE_ENABLE_OTA -/* -** Allocate and populate the output arrays returned by the -** sqlite3_index_writer() function. -*/ -static int indexWriterOutputVars( - sqlite3 *db, - Index *pIdx, - const char ***pazColl, /* OUT: Array of collation sequences */ - int **paiCol, /* OUT: Array of column indexes */ - int *pnCol /* OUT: Total columns in index keys */ -){ - Table *pTbl = pIdx->pTable; /* Table index is attached to */ - Index *pPk = 0; - int nByte = 0; /* Total bytes of space to allocate */ - int i; /* Iterator variable */ - - int *aiCol; - const char **azColl; - char *pCsr; - - if( !HasRowid(pTbl) ){ - pPk = sqlite3PrimaryKeyIndex(pTbl); - } - - for(i=0; inColumn; i++){ - const char *zColl = 0; - if( inKeyCol ){ - zColl = pIdx->azColl[i]; - }else if( pPk ){ - zColl = pPk->azColl[i-pIdx->nKeyCol]; - } - if( zColl==0 ) zColl = "BINARY"; - nByte += sqlite3Strlen30(zColl) + 1; - } - nByte += (pIdx->nColumn) * (sizeof(const char*) + sizeof(int)); - - /* Populate the output variables */ - *pazColl = azColl = (const char**)sqlite3DbMallocZero(db, nByte); - if( azColl==0 ) return SQLITE_NOMEM; - *paiCol = aiCol = (int*)&azColl[pIdx->nColumn]; - *pnCol = pIdx->nColumn; - pCsr = (char*)&aiCol[pIdx->nColumn]; - - for(i=0; inColumn; i++){ - const char *zColl = 0; - int nColl; - int iCol = pTbl->iPKey; - if( inKeyCol ){ - zColl = pIdx->azColl[i]; - iCol = pIdx->aiColumn[i]; - }else if( pPk ){ - zColl = pPk->azColl[i-pIdx->nKeyCol]; - iCol = pPk->aiColumn[i-pIdx->nKeyCol]; - } - if( zColl==0 ) zColl = "BINARY"; - - aiCol[i] = iCol; - azColl[i] = pCsr; - nColl = 1 + sqlite3Strlen30(zColl); - memcpy(pCsr, zColl, nColl); - pCsr += nColl; - } - - return SQLITE_OK; -} - -/* -** Prepare and return an SQL statement handle that can be used to write -** directly to an index b-tree. -*/ -int sqlite3_index_writer( - sqlite3 *db, - int bDelete, - const char *zIndex, - sqlite3_stmt **ppStmt, - const char ***pazColl, /* OUT: Array of collation sequences */ - int **paiCol, /* OUT: Array of column indexes */ - int *pnCol /* OUT: Total columns in index keys */ -){ - int rc = SQLITE_OK; - Parse *pParse = 0; - Index *pIdx = 0; /* The index to write to */ - Table *pTab; - int i; /* Used to iterate through index columns */ - Vdbe *v = 0; - int regRec; /* Register to assemble record in */ - const char *zAffinity = 0; /* Affinity string for the current index */ - - sqlite3_mutex_enter(db->mutex); - sqlite3BtreeEnterAll(db); - - /* Allocate the parse context */ - pParse = sqlite3StackAllocRaw(db, sizeof(*pParse)); - if( !pParse ) goto index_writer_out; - memset(pParse, 0, sizeof(Parse)); - pParse->db = db; - - /* Allocate the Vdbe */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto index_writer_out; - - /* Find the index to write to */ - pIdx = sqlite3FindIndex(db, zIndex, "main"); - if( pIdx==0 ){ - sqlite3ErrorMsg(pParse, "no such index: %s", zIndex); - goto index_writer_out; - } - pTab = pIdx->pTable; - zAffinity = sqlite3IndexAffinityStr(v, pIdx); - - rc = indexWriterOutputVars(db, pIdx, pazColl, paiCol, pnCol); - if( rc!=SQLITE_OK ) goto index_writer_out; - - /* Add an OP_Noop to the VDBE program. Then store a pointer to the - ** output array *paiCol as its P4 value. This is so that the array - ** is automatically deleted when the user finalizes the statement. The - ** OP_Noop serves no other purpose. */ - sqlite3VdbeAddOp0(v, OP_Noop); - sqlite3VdbeChangeP4(v, -1, (const char*)(*pazColl), P4_INTARRAY); - - sqlite3BeginWriteOperation(pParse, 0, 0); - - /* Open a write cursor on the index */ - pParse->nTab = 1; - sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, pIdx->tnum, 0); - sqlite3VdbeSetP4KeyInfo(pParse, pIdx); - - /* Create the record to insert into the index. Store it in register regRec. */ - pParse->nVar = pIdx->nColumn; - pParse->nMem = pIdx->nColumn; - for(i=1; i<=pIdx->nColumn; i++){ - sqlite3VdbeAddOp2(v, OP_Variable, i, i); - } - regRec = ++pParse->nMem; - - /* If this is a rowid table, check that the rowid field is an integer. */ - if( HasRowid(pTab) ){ - sqlite3VdbeAddOp2(v, OP_MustBeInt, pIdx->nColumn, 0); - VdbeCoverageNeverTaken(v); - } - - if( bDelete==0 ){ - sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, pIdx->nColumn, regRec, zAffinity, 0); - - /* If this is a UNIQUE index, check the constraint. */ - if( pIdx->onError ){ - int addr = sqlite3VdbeAddOp4Int(v, OP_NoConflict, 0, 0, 1, pIdx->nKeyCol); - VdbeCoverage(v); - sqlite3UniqueConstraint(pParse, SQLITE_ABORT, pIdx); - sqlite3VdbeJumpHere(v, addr); - } - - /* Code the IdxInsert to write to the b-tree index. */ - sqlite3VdbeAddOp2(v, OP_IdxInsert, 0, regRec); - }else{ - /* Code the IdxDelete to remove the entry from the b-tree index. */ - sqlite3VdbeAddOp4(v, OP_Affinity, 1, pIdx->nColumn, 0, zAffinity, 0); - sqlite3VdbeAddOp3(v, OP_IdxDelete, 0, 1, pIdx->nColumn); - } - sqlite3FinishCoding(pParse); - -index_writer_out: - if( rc==SQLITE_OK && db->mallocFailed==0 ){ - *ppStmt = (sqlite3_stmt*)v; - }else{ - *ppStmt = 0; - if( v ) sqlite3VdbeFinalize(v); - } - - sqlite3ParserReset(pParse); - sqlite3StackFree(db, pParse); - sqlite3BtreeLeaveAll(db); - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); - return rc; -} -#endif /* SQLITE_ENABLE_OTA */ - #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 149a1bfff7..0d93704d70 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -318,11 +318,6 @@ set pragma_def { NAME: pager_ota_mode IF: defined(SQLITE_ENABLE_OTA) - - NAME: ota_mode - TYPE: FLAG - ARG: SQLITE_OtaMode - IF: defined(SQLITE_ENABLE_OTA) } fconfigure stdout -translation lf set name {} -- 2.47.2