1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Remove "PRAGMA ota_mode".

FossilOrigin-Name: 1c111447a07687c30ed4ad5a6c27a169c85b7ea6
This commit is contained in:
dan
2015-02-03 15:56:08 +00:00
parent 3b660d7da3
commit 75fda9b395
16 changed files with 358 additions and 651 deletions

View File

@@ -63,19 +63,29 @@ do_execsql_test 2.0 {
CREATE INDEX i1 ON x1(b, c); CREATE INDEX i1 ON x1(b, c);
} {} } {}
do_test 2.1 { foreach {tn otadb} {
sqlite3 db2 ota.db 1 {
db2 eval {
CREATE TABLE data_x1(a, b, c, ota_control); CREATE TABLE data_x1(a, b, c, ota_control);
INSERT INTO data_x1 VALUES(NULL, 'a', 'b', 0); 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 { 2 {
PRAGMA integrity_check; CREATE TABLE data_x1(c, b, a, ota_control);
} {ok} 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. # Test that missing columns are detected.
@@ -102,4 +112,28 @@ do_execsql_test 2.2 {
PRAGMA integrity_check; PRAGMA integrity_check;
} {ok} } {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 finish_test

View File

@@ -124,110 +124,5 @@ do_catchsql_test 1.5.4 {
SELECT * FROM t1; SELECT * FROM t1;
} {1 {database is locked}} } {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 finish_test

View File

@@ -102,8 +102,9 @@ struct OtaObjIter {
sqlite3_stmt *pTblIter; /* Iterate through tables */ sqlite3_stmt *pTblIter; /* Iterate through tables */
sqlite3_stmt *pIdxIter; /* Index iterator */ sqlite3_stmt *pIdxIter; /* Index iterator */
int nTblCol; /* Size of azTblCol[] array */ 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 */ char **azTblType; /* Array of column types */
int *aiTblOrder; /* Order of columns in target table */
unsigned char *abTblPk; /* Array of flags - true for PK columns */ unsigned char *abTblPk; /* Array of flags - true for PK columns */
int eType; int eType;
@@ -128,11 +129,18 @@ struct OtaObjIter {
/* /*
** Values for OtaObjIter.eType ** 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_NONE 1
#define OTA_PK_EXTERNAL 2 /* Table has an external primary key index */ #define OTA_PK_IPK 2
#define OTA_PK_NONE 3 /* Table has no PK (use rowid) */ #define OTA_PK_EXTERNAL 3
#define OTA_PK_VTAB 4 /* Table is a virtual table (use rowid) */ #define OTA_PK_WITHOUT_ROWID 4
#define OTA_PK_VTAB 5
/* /*
** OTA handle. ** OTA handle.
@@ -225,7 +233,7 @@ static int prepareFreeAndCollectError(
/* /*
** Free the OtaObjIter.azTblCol[] and OtaObjIter.abTblPk[] arrays allocated ** 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){ static void otaObjIterFreeCols(OtaObjIter *pIter){
int i; int i;
@@ -236,6 +244,7 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){
sqlite3_free(pIter->azTblCol); sqlite3_free(pIter->azTblCol);
pIter->azTblCol = 0; pIter->azTblCol = 0;
pIter->azTblType = 0; pIter->azTblType = 0;
pIter->aiTblOrder = 0;
pIter->abTblPk = 0; pIter->abTblPk = 0;
pIter->nTblCol = 0; pIter->nTblCol = 0;
sqlite3_free(pIter->zMask); 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 */ /* Free any SQLite statements used while processing the previous object */
otaObjIterClearStatements(pIter); 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 ){ if( rc==SQLITE_OK ){
otaObjIterFreeCols(pIter); if( pIter->bCleanup ){
pIter->bCleanup = 0; otaObjIterFreeCols(pIter);
rc = sqlite3_step(pIter->pTblIter); pIter->bCleanup = 0;
if( rc!=SQLITE_ROW ){ rc = sqlite3_step(pIter->pTblIter);
rc = sqlite3_reset(pIter->pTblIter); if( rc!=SQLITE_ROW ){
pIter->zTbl = 0; 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{ }else{
pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0); if( pIter->zIdx==0 ){
rc = SQLITE_OK; sqlite3_bind_text(pIter->pIdxIter, 1, pIter->zTbl, -1, SQLITE_STATIC);
} }
}else{ rc = sqlite3_step(pIter->pIdxIter);
if( pIter->zIdx==0 ){ if( rc!=SQLITE_ROW ){
sqlite3_bind_text(pIter->pIdxIter, 1, pIter->zTbl, -1, SQLITE_STATIC); rc = sqlite3_reset(pIter->pIdxIter);
} pIter->bCleanup = 1;
rc = sqlite3_step(pIter->pIdxIter); pIter->zIdx = 0;
if( rc!=SQLITE_ROW ){ }else{
rc = sqlite3_reset(pIter->pIdxIter); pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0);
pIter->bCleanup = 1; pIter->tnum = sqlite3_column_int(pIter->pIdxIter, 1);
pIter->zIdx = 0; pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2);
}else{ rc = SQLITE_OK;
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)); memset(pIter, 0, sizeof(OtaObjIter));
rc = prepareAndCollectError(p->db, &pIter->pTblIter, &p->zErrmsg, rc = prepareAndCollectError(p->db, &pIter->pTblIter, &p->zErrmsg,
"SELECT substr(name, 6) FROM ota.sqlite_master " "SELECT substr(a.name, 6), b.rootpage FROM ota.sqlite_master AS a "
"WHERE type='table' AND name LIKE 'data_%'" "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 ){ if( rc==SQLITE_OK ){
@@ -353,53 +376,6 @@ static int otaObjIterFirst(sqlite3ota *p, OtaObjIter *pIter){
return otaObjIterNext(p, 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; i<nName; i++){
if( zName[i]=='`' ) *p++ = '`';
*p++ = zName[i];
}
*p++ = '`';
*p++ = '\0';
}
return zRet;
}
/*
** Argument zName points to a column name. Argument zQuoted also points
** to a column name, but one that has been quoted using otaQuoteName().
** Return true if the column names are the same, or false otherwise.
*/
static int otaMatchName(const char *zName, const char *zQuoted){
const char *p = zName;
const char *q = &zQuoted[1];
while( 1 ){
if( *q=='`' ) q++;
if( sqlite3_strnicmp(q, p, 1) ) return 0;
if( !*q ) break;
p++;
q++;
}
return 1;
}
/* /*
** Argument zFmt is a sqlite3_mprintf() style format string. The trailing ** Argument zFmt is a sqlite3_mprintf() style format string. The trailing
** arguments are the usual subsitution values. This function performs ** arguments are the usual subsitution values. This function performs
@@ -432,7 +408,7 @@ static int otaMPrintfExec(sqlite3ota *p, const char *zFmt, ...){
** error code in the OTA handle passed as the first argument. ** error code in the OTA handle passed as the first argument.
*/ */
static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){ static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
int nByte = sizeof(char*) * nCol * 2 + sizeof(unsigned char*) * nCol; int nByte = (sizeof(char*) * 2 + sizeof(int) + sizeof(unsigned char)) * nCol;
char **azNew; char **azNew;
assert( p->rc==SQLITE_OK ); assert( p->rc==SQLITE_OK );
@@ -441,7 +417,8 @@ static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
memset(azNew, 0, nByte); memset(azNew, 0, nByte);
pIter->azTblCol = azNew; pIter->azTblCol = azNew;
pIter->azTblType = &azNew[nCol]; 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{ }else{
p->rc = SQLITE_NOMEM; 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[], ** If they are not already populated, populate the pIter->azTblCol[],
** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to ** 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 ** 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 ** an error does occur, an error code and error message are also left in
** the OTA handle. ** the OTA handle.
*/ */
static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){
if( pIter->azTblCol==0 ){ if( pIter->azTblCol==0 ){
sqlite3_stmt *pStmt = 0; sqlite3_stmt *pStmt = 0;
int nCol = 0; int nCol = 0;
int i; /* for() loop iterator variable */ int i; /* for() loop iterator variable */
int rc2; /* sqlite3_finalize() return value */ int rc2; /* sqlite3_finalize() return value */
int bOtaRowid = 0; /* If input table has column "ota_rowid" */ 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 ); 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 /* Populate the azTblCol[] and nTblCol variables based on the columns
** of the input table. Ignore any input table columns that begin with ** 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 && i<nCol; i++){ for(i=0; p->rc==SQLITE_OK && i<nCol; i++){
const char *zName = (const char*)sqlite3_column_name(pStmt, i); const char *zName = (const char*)sqlite3_column_name(pStmt, i);
if( sqlite3_strnicmp("ota_", zName, 4) ){ if( sqlite3_strnicmp("ota_", zName, 4) ){
char *zCopy = otaQuoteName(zName); char *zCopy = otaStrndup(zName, -1, &p->rc);
pIter->azTblCol[pIter->nTblCol++] = zCopy; pIter->azTblCol[pIter->nTblCol++] = zCopy;
if( zCopy==0 ) p->rc = SQLITE_NOMEM;
} }
else if( 0==sqlite3_stricmp("ota_rowid", zName) ){ else if( 0==sqlite3_stricmp("ota_rowid", zName) ){
bOtaRowid = 1; bOtaRowid = 1;
@@ -535,9 +494,19 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){
sqlite3_finalize(pStmt); sqlite3_finalize(pStmt);
pStmt = 0; 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 /* Check that all non-HIDDEN columns in the destination table are also
** present in the input table. Populate the abTblPk[] array at the ** present in the input table. Populate the abTblPk[], azTblType[] and
** same time. */ ** aiTblOrder[] arrays at the same time. */
if( p->rc==SQLITE_OK ){ if( p->rc==SQLITE_OK ){
p->rc = prepareFreeAndCollectError(p->db, &pStmt, &p->zErrmsg, p->rc = prepareFreeAndCollectError(p->db, &pStmt, &p->zErrmsg,
sqlite3_mprintf("PRAGMA main.table_info(%Q)", pIter->zTbl) 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) ){ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zName = (const char*)sqlite3_column_text(pStmt, 1); const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
for(i=0; i<pIter->nTblCol; i++){ for(i=0; i<pIter->nTblCol; i++){
if( otaMatchName(zName, pIter->azTblCol[i]) ) break; if( 0==strcmp(zName, pIter->azTblCol[i]) ) break;
} }
if( i==pIter->nTblCol ){ if( i==pIter->nTblCol ){
p->rc = SQLITE_ERROR; p->rc = SQLITE_ERROR;
@@ -556,37 +525,34 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){
}else{ }else{
int iPk = sqlite3_column_int(pStmt, 5); int iPk = sqlite3_column_int(pStmt, 5);
const char *zType = (const char*)sqlite3_column_text(pStmt, 2); const char *zType = (const char*)sqlite3_column_text(pStmt, 2);
pIter->aiTblOrder[i] = iOrder++;
pIter->azTblType[i] = otaStrndup(zType, -1, &p->rc); pIter->azTblType[i] = otaStrndup(zType, -1, &p->rc);
pIter->abTblPk[i] = (iPk!=0); pIter->abTblPk[i] = (iPk!=0);
if( iPk ){ }
pIter->eType = (iPk<0) ? OTA_PK_EXTERNAL : OTA_PK_REAL; }
while( iOrder<pIter->nTblCol ){
for(i=0; i<pIter->nTblCol; i++){
if( pIter->aiTblOrder[i]==0 ){
pIter->aiTblOrder[i] = iOrder++;
continue;
} }
} }
} }
/* 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); rc2 = sqlite3_finalize(pStmt);
if( p->rc==SQLITE_OK ) p->rc = rc2; 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;
}
}else if( bOtaRowid ){
p->rc = SQLITE_ERROR;
p->zErrmsg = sqlite3_mprintf(
"table data_%q may not have ota_rowid column", pIter->zTbl
);
}
}
} }
return p->rc; 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 ** 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 ** string containing some SQL clause or list based on one or more of the
** column names currently stored in the pIter->azTblCol[] array. ** 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( static char *otaObjIterGetCollist(
sqlite3ota *p, /* OTA object */ sqlite3ota *p, /* OTA object */
OtaObjIter *pIter, /* Object iterator for column names */ 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 */
){ ){
char *zList = 0; char *zList = 0;
if( p->rc==SQLITE_OK ){ const char *zSep = "";
const char *zSep = ""; int i;
int i; for(i=0; i<pIter->nTblCol; i++){
for(i=0; i<nCol; i++){ const char *z = pIter->azTblCol[i];
int iCol = aiCol ? aiCol[i] : i; zList = otaMPrintfAndCollectError(p, "%z%s\"%w\"", zList, zSep, z);
char *zCol = (iCol>=0 ? pIter->azTblCol[iCol] : "ota_rowid"); zSep = ", ";
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;
}
}
} }
return zList; return zList;
} }
@@ -709,7 +633,7 @@ static char *otaObjIterGetIndexCols(
char *zImpPK = 0; /* String to return via *pzImposterPK */ char *zImpPK = 0; /* String to return via *pzImposterPK */
char *zWhere = 0; /* String to return via *pzWhere */ char *zWhere = 0; /* String to return via *pzWhere */
int nBind = 0; /* Value to return via *pnBind */ 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 */ const char *zAnd = ""; /* Set to " AND " later on */
sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = ? */ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = ? */
@@ -729,7 +653,7 @@ static char *otaObjIterGetIndexCols(
if( iCid<0 ){ if( iCid<0 ){
/* An integer primary key. If the table has an explicit IPK, use /* An integer primary key. If the table has an explicit IPK, use
** its name. Otherwise, use "ota_rowid". */ ** its name. Otherwise, use "ota_rowid". */
if( pIter->eType==OTA_PK_REAL ){ if( pIter->eType==OTA_PK_IPK ){
int i; int i;
for(i=0; i<pIter->nTblCol && pIter->abTblPk[i]==0; i++); for(i=0; i<pIter->nTblCol && pIter->abTblPk[i]==0; i++);
assert( i<pIter->nTblCol ); assert( i<pIter->nTblCol );
@@ -743,16 +667,16 @@ static char *otaObjIterGetIndexCols(
zType = pIter->azTblType[iCid]; 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) ){ 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( 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); zWhere = sqlite3_mprintf("%z%sc%d IS ?", zWhere, zAnd, nBind);
if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM; if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM;
zComma = ", "; zCom = ", ";
zAnd = " AND "; zAnd = " AND ";
nBind++; nBind++;
} }
@@ -800,7 +724,8 @@ static char *otaObjIterGetOldlist(
const char *zS = ""; const char *zS = "";
int i; int i;
for(i=0; i<pIter->nTblCol; i++){ for(i=0; i<pIter->nTblCol; 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 = ", "; zS = ", ";
if( zList==0 ){ if( zList==0 ){
p->rc = SQLITE_NOMEM; p->rc = SQLITE_NOMEM;
@@ -831,20 +756,18 @@ static char *otaObjIterGetWhere(
OtaObjIter *pIter OtaObjIter *pIter
){ ){
char *zList = 0; char *zList = 0;
if( p->rc==SQLITE_OK ){ if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){
if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){ zList = otaMPrintfAndCollectError(p, "_rowid_ = ?%d", pIter->nTblCol+1);
zList = otaMPrintfAndCollectError(p, "_rowid_ = ?%d", pIter->nTblCol+1); }else{
}else{ const char *zSep = "";
const char *zSep = ""; int i;
int i; for(i=0; i<pIter->nTblCol; i++){
for(i=0; i<pIter->nTblCol; i++){ if( pIter->abTblPk[i] ){
if( pIter->abTblPk[i] ){ const char *zCol = pIter->azTblCol[i];
const char *zCol = pIter->azTblCol[i]; zList = otaMPrintfAndCollectError(
zList = otaMPrintfAndCollectError( p, "%z%s\"%w\"=?%d", zList, zSep, zCol, i+1
p, "%z%s%s=?%d", zList, zSep, zCol, i+1 );
); zSep = " AND ";
zSep = " AND ";
}
} }
} }
} }
@@ -880,13 +803,14 @@ static char *otaObjIterGetSetlist(
for(i=0; i<pIter->nTblCol; i++){ for(i=0; i<pIter->nTblCol; i++){
char c = zMask[i]; char c = zMask[i];
if( c=='x' ){ if( c=='x' ){
zList = otaMPrintfAndCollectError(p, "%z%s%s=?%d", zList = otaMPrintfAndCollectError(p, "%z%s\"%w\"=?%d",
zList, zSep, pIter->azTblCol[i], i+1 zList, zSep, pIter->azTblCol[i], i+1
); );
zSep = ", "; zSep = ", ";
} }
if( c=='d' ){ 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 zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
); );
zSep = ", "; zSep = ", ";
@@ -915,6 +839,81 @@ static char *otaObjIterGetBindlist(sqlite3ota *p, int nBind){
return zRet; 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 && iCol<pIter->nTblCol; 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; iCol<pIter->nTblCol; 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 ** Ensure that the SQLite statement handles required to update the
** target database object currently indicated by the iterator passed ** 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 */ int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */
){ ){
assert( pIter->bCleanup==0 ); 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; const int tnum = pIter->tnum;
char *zCollist = 0; /* List of indexed columns */ char *zCollist = 0; /* List of indexed columns */
char **pz = &p->zErrmsg; char **pz = &p->zErrmsg;
@@ -939,9 +938,9 @@ static int otaObjIterPrepareAll(
} }
if( zIdx ){ if( zIdx ){
char *zImposterCols = 0; char *zImposterCols = 0; /* Columns for imposter table */
char *zImposterPK = 0; char *zImposterPK = 0; /* Primary key declaration for imposter */
char *zWhere = 0; char *zWhere = 0; /* WHERE clause on PK columns */
char *zBind = 0; char *zBind = 0;
int nBind = 0; int nBind = 0;
@@ -1005,13 +1004,15 @@ static int otaObjIterPrepareAll(
sqlite3_free(zBind); sqlite3_free(zBind);
}else{ }else{
int bOtaRowid = (pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE); 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 *zWhere = otaObjIterGetWhere(p, pIter);
char *zOldlist = otaObjIterGetOldlist(p, pIter, "old"); char *zOldlist = otaObjIterGetOldlist(p, pIter, "old");
char *zNewlist = otaObjIterGetOldlist(p, pIter, "new"); 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; pIter->nCol = pIter->nTblCol;
/* Create the SELECT statement to read keys from data_xxx */ /* 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 */ /* Create the INSERT statement to write to the target PK b-tree */
if( p->rc==SQLITE_OK ){ if( p->rc==SQLITE_OK ){
p->rc = prepareFreeAndCollectError(p->db, &pIter->pInsert, pz, p->rc = prepareFreeAndCollectError(p->db, &pIter->pInsert, pz,
sqlite3_mprintf( sqlite3_mprintf(
"INSERT INTO main.%Q(%s%s) VALUES(%s)", "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 ){ if( p->rc==SQLITE_OK ){
p->rc = prepareFreeAndCollectError(p->db, &pIter->pDelete, pz, p->rc = prepareFreeAndCollectError(p->db, &pIter->pDelete, pz,
sqlite3_mprintf( 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 " "CREATE TABLE IF NOT EXISTS ota.'ota_tmp_%q' AS "
"SELECT *%s FROM ota.'data_%q' WHERE 0;" "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 " "BEGIN "
" INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(2, %s);" " INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(2, %s);"
"END;" "END;"
"CREATE TEMP TRIGGER ota_update1_%q BEFORE UPDATE ON main.%Q " "CREATE TEMP TRIGGER ota_update1_tr BEFORE UPDATE ON ota_imposter "
"BEGIN " "BEGIN "
" INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(2, %s);" " INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(2, %s);"
"END;" "END;"
"CREATE TEMP TRIGGER ota_update2_%q AFTER UPDATE ON main.%Q " "CREATE TEMP TRIGGER ota_update2_tr AFTER UPDATE ON ota_imposter "
"BEGIN " "BEGIN "
" INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(3, %s);" " INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(3, %s);"
"END;" "END;"
, zTbl, (pIter->eType==OTA_PK_EXTERNAL ? ", 0 AS ota_rowid" : "") , zTbl, (pIter->eType==OTA_PK_EXTERNAL ? ", 0 AS ota_rowid" : "")
, zTbl, , zTbl,
zTbl, zTbl, zTbl, zCollist, zOtaRowid, zOldlist, zTbl, zCollist, zOtaRowid, zOldlist,
zTbl, zTbl, zTbl, zCollist, zOtaRowid, zOldlist, zTbl, zCollist, zOtaRowid, zOldlist,
zTbl, zTbl, zTbl, zCollist, zOtaRowid, zNewlist zTbl, zCollist, zOtaRowid, zNewlist
); );
if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){ if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){
otaMPrintfExec(p, 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 " "BEGIN "
" INSERT INTO 'ota_tmp_%q'(ota_control, %s, ota_rowid)" " INSERT INTO 'ota_tmp_%q'(ota_control, %s, ota_rowid)"
" VALUES(0, %s);" " VALUES(0, %s);"
"END;" "END;"
, zTbl, zTbl, zTbl, zCollist, zNewlist , zTbl, zCollist, zNewlist
); );
} }
}else if( p->rc==SQLITE_OK ){ }else if( p->rc==SQLITE_OK ){
@@ -1133,8 +1138,9 @@ static int otaGetUpdateStmt(
sqlite3_finalize(pIter->pUpdate); sqlite3_finalize(pIter->pUpdate);
pIter->pUpdate = 0; pIter->pUpdate = 0;
if( p->rc==SQLITE_OK ){ if( p->rc==SQLITE_OK ){
zUpdate = sqlite3_mprintf("UPDATE %Q SET %s WHERE %s", zUpdate = sqlite3_mprintf("UPDATE \"%w\" SET %s WHERE %s",
pIter->zTbl, zSet, zWhere (pIter->eType==OTA_PK_VTAB ? pIter->zTbl : "ota_imposter"),
zSet, zWhere
); );
p->rc = prepareFreeAndCollectError( p->rc = prepareFreeAndCollectError(
p->db, &pIter->pUpdate, &p->zErrmsg, zUpdate p->db, &pIter->pUpdate, &p->zErrmsg, zUpdate
@@ -1337,9 +1343,22 @@ static int otaStep(sqlite3ota *p){
} }
for(i=0; i<pIter->nCol; i++){ for(i=0; i<pIter->nCol; 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 ){ if( eType==SQLITE_DELETE && pIter->zIdx==0 && pIter->abTblPk[i]==0 ){
continue; continue;
} }
pVal = sqlite3_column_value(pIter->pSelect, i); pVal = sqlite3_column_value(pIter->pSelect, i);
sqlite3_bind_value(pWriter, i+1, pVal); sqlite3_bind_value(pWriter, i+1, pVal);
} }
@@ -1383,6 +1402,7 @@ static int otaStep(sqlite3ota *p){
} }
} }
step_out:
return p->rc; return p->rc;
} }

View File

@@ -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. C Remove\s"PRAGMA\sota_mode".
D 2015-01-31T20:42:04.027 D 2015-02-03T15:56:08.271
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610 F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -128,15 +128,15 @@ F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91
F ext/ota/ota1.test d76b9ec77437759e9da0ff4abe9c070bb9f4eae1 F ext/ota/ota1.test d76b9ec77437759e9da0ff4abe9c070bb9f4eae1
F ext/ota/ota10.test ab815dff9cef7248c504f06b888627d236f25e9c F ext/ota/ota10.test ab815dff9cef7248c504f06b888627d236f25e9c
F ext/ota/ota2.test 2829bc08ffbb71b605392a68fedfd554763356a7 F ext/ota/ota2.test 2829bc08ffbb71b605392a68fedfd554763356a7
F ext/ota/ota3.test 71bd8cc0cf8d7e7d9bb11a1fcc238320a5a9d8c8 F ext/ota/ota3.test a77efbce7723332eb688d2b28bf18204fc9614d7
F ext/ota/ota4.test 60f897f329a6782ef2f24862640acf3c52e48077 F ext/ota/ota4.test 82434aa39c9acca6cd6317f6b0ab07b0ec6c2e7d
F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
F ext/ota/ota6.test 82f1f757ec9b2ad07d6de4060b8e3ba8e44dfdd3 F ext/ota/ota6.test 82f1f757ec9b2ad07d6de4060b8e3ba8e44dfdd3
F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a
F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b
F ext/ota/otafault.test 508ba87c83d632670ac0f94371a465d4bb4d49dd 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/ota/sqlite3ota.h ce378c0c503f625611713133f9c79704ea4ee7a4
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f
@@ -188,7 +188,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
F src/btree.c ddca0ae681c49813a4bfd88d5f922fac71e0ffaa F src/btree.c 2a1245df0356a229bcd0fd87a8536b5067f16e82
F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474 F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474
F src/btreeInt.h a3d0ae1d511365e1a2b76ad10960dbe55c286f34 F src/btreeInt.h a3d0ae1d511365e1a2b76ad10960dbe55c286f34
F src/build.c eefaa4f1d86bc3c08023a61fdd1e695b47796975 F src/build.c eefaa4f1d86bc3c08023a61fdd1e695b47796975
@@ -196,7 +196,7 @@ F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463 F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463
F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887 F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887
F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac
F src/delete.c e68b70ac41dcf6e92a813d860fa984fcd9aec042 F src/delete.c bd1a91ddd247ce13004075251e0b7fe2bf9925ef
F src/expr.c abe930897ccafae3819fd2855cbc1b00c262fd12 F src/expr.c abe930897ccafae3819fd2855cbc1b00c262fd12
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12 F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12
@@ -205,12 +205,12 @@ F src/global.c 12561d70a1b25f67b21154622bb1723426724f75
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c fef86ab8218cf0d926db93280b9eb5b583981353 F src/insert.c 5b9243a33726008cc4132897d2be371db12a13be
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660
F src/main.c c4cb192ebf0bcc975648ae05ac40bc1f40018c52 F src/main.c 55d548a2c2f32d27366968c394d091475f7ea00a
F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987 F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
@@ -238,7 +238,7 @@ F src/parse.y c5d0d964f9ac023e8154cad512e54b0b6058e086
F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf
F src/pragma.c e49831e54c72894cce08702fe2e127e5c53d90f0 F src/pragma.c 26fc55619109828c9b7add4cfa8a961b6f4c456d
F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9
F src/printf.c 05edc41450d0eb2c05ef7db113bf32742ae65325 F src/printf.c 05edc41450d0eb2c05ef7db113bf32742ae65325
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
@@ -246,15 +246,15 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c 1f2087523007c42900ffcbdeaef06a23ad9329fc F src/select.c 1f2087523007c42900ffcbdeaef06a23ad9329fc
F src/shell.c 22b4406b0b59efd14b3b351a5809dda517df6d30 F src/shell.c 22b4406b0b59efd14b3b351a5809dda517df6d30
F src/sqlite.h.in 78e493f94202d8083dd270e257786a6311d1fb3b F src/sqlite.h.in 8913937ba11415bf369818431700adf3a921fb18
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
F src/sqliteInt.h 66180aa8f81155a7f391bbf759ee5a3b61d2f89f F src/sqliteInt.h 57f8f45028598cc2877fc08ac03b402242242c68
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/status.c 81712116e826b0089bb221b018929536b2b5406f
F src/table.c e7a09215315a978057fb42c640f890160dbcc45e F src/table.c e7a09215315a978057fb42c640f890160dbcc45e
F src/tclsqlite.c b321464aba1fff1ed9317ebc82a1a94887f97af8 F src/tclsqlite.c b321464aba1fff1ed9317ebc82a1a94887f97af8
F src/test1.c 313567541c980e45220d6faed393b6ad454f8ecd F src/test1.c ce8ea168800d129acb2c0afdf2831ddf8667e082
F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d
F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622 F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
@@ -302,7 +302,7 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481
F src/tokenize.c e00458c9938072b0ea711c850b8dcf4ddcb5fe18 F src/tokenize.c e00458c9938072b0ea711c850b8dcf4ddcb5fe18
F src/trigger.c 6dcdf46a21acf4d4e011c809b2c971e63f797a1a F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f
F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e
@@ -312,7 +312,7 @@ F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78
F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71 F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71
F src/vdbeaux.c 97911edb61074b871ec4aa2d6bb779071643dee5 F src/vdbeaux.c 97911edb61074b871ec4aa2d6bb779071643dee5
F src/vdbeblob.c ad7787440295e43c12248dc48cde4b13e5df4ca0 F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778
F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f
F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2 F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2
F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
@@ -1218,7 +1218,7 @@ F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f
F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkpragmatab.tcl 5a401a3f5461fedb2e3230eb9908a18d485fefea F tool/mkpragmatab.tcl aea392b69f8e72715760629cd50411d37bc85de4
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 9ef48e1748dce7b844f67e2450ff9dfeb0fb4ab5 F tool/mksqlite3c-noext.tcl 9ef48e1748dce7b844f67e2450ff9dfeb0fb4ab5
F tool/mksqlite3c.tcl cfde806851c413db7689b9cb74a4eeb92539c601 F tool/mksqlite3c.tcl cfde806851c413db7689b9cb74a4eeb92539c601
@@ -1254,7 +1254,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P f9b6dc77021ee421bffd5697d5d337d3bbd07eb9 P cdaeab467f6aa3217be161377a9b78a4eec37093
R 907483269529ba471a525b7f8d05bc2e R 2703aba199c695992db82956950982ca
U dan U dan
Z 87f206a3330dd276f74650f9e68af8ed Z fae9dc4e5e5c1a2d2a162b422a05ccf9

View File

@@ -1 +1 @@
cdaeab467f6aa3217be161377a9b78a4eec37093 1c111447a07687c30ed4ad5a6c27a169c85b7ea6

View File

@@ -151,8 +151,7 @@ static int hasSharedCacheTableLock(
** and has the read-uncommitted flag set, then no lock is required. ** and has the read-uncommitted flag set, then no lock is required.
** Return true immediately. ** Return true immediately.
*/ */
if( (pBtree->db->flags & SQLITE_OtaMode) if( (pBtree->sharable==0)
|| (pBtree->sharable==0)
|| (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted))
){ ){
return 1; return 1;

View File

@@ -730,9 +730,6 @@ void sqlite3GenerateRowIndexDelete(
Vdbe *v; /* The prepared statement under construction */ Vdbe *v; /* The prepared statement under construction */
Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */ 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; v = pParse->pVdbe;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){

View File

@@ -1365,10 +1365,6 @@ void sqlite3GenerateConstraintChecks(
int iThisCur; /* Cursor for this UNIQUE index */ int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ 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( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
if( bAffinityDone==0 ){ if( bAffinityDone==0 ){
sqlite3TableAffinity(v, pTab, regNewData+1); sqlite3TableAffinity(v, pTab, regNewData+1);
@@ -1560,15 +1556,6 @@ void sqlite3CompleteInsertion(
assert( pTab->pSelect==0 ); /* This table is not a VIEW */ assert( pTab->pSelect==0 ); /* This table is not a VIEW */
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( aRegIdx[i]==0 ) continue; 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; bAffinityDone = 1;
if( pIdx->pPartIdxWhere ){ if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);

View File

@@ -3654,6 +3654,45 @@ int sqlite3_test_control(int op, ...){
sqlite3_mutex_leave(db->mutex); sqlite3_mutex_leave(db->mutex);
break; 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); va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */ #endif /* SQLITE_OMIT_BUILTIN_TEST */

View File

@@ -320,14 +320,6 @@ static const struct sPragmaNames {
/* ePragTyp: */ PragTyp_MMAP_SIZE, /* ePragTyp: */ PragTyp_MMAP_SIZE,
/* ePragFlag: */ 0, /* ePragFlag: */ 0,
/* iArg: */ 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", { /* zName: */ "page_count",
/* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragTyp: */ PragTyp_PAGE_COUNT,
/* ePragFlag: */ PragFlag_NeedSchema, /* ePragFlag: */ PragFlag_NeedSchema,
@@ -496,7 +488,7 @@ static const struct sPragmaNames {
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif #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. /* End of the automatically generated pragma table.
***************************************************************************/ ***************************************************************************/
@@ -1545,9 +1537,6 @@ void sqlite3Pragma(
k = 1; k = 1;
}else{ }else{
for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} 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_Integer, k, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);

View File

@@ -6266,7 +6266,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_IMPOSTER 25
#define SQLITE_TESTCTRL_LAST 25 #define SQLITE_TESTCTRL_TBLTYPE 26
#define SQLITE_TESTCTRL_LAST 26
/* /*
** CAPI3REF: SQLite Runtime Status ** CAPI3REF: SQLite Runtime Status
@@ -7585,66 +7586,6 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
*/ */
SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); 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. ** Incremental checkpoint API.
** **

View File

@@ -1207,12 +1207,6 @@ struct sqlite3 {
#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */ #define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
#define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */ #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 ** Bits of the sqlite3.dbOptFlags field that are used by the
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to

View File

@@ -6922,11 +6922,11 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_user_change", test_user_change, 0 }, { "sqlite3_user_change", test_user_change, 0 },
{ "sqlite3_user_delete", test_user_delete, 0 }, { "sqlite3_user_delete", test_user_delete, 0 },
#endif #endif
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
{ "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 }, { "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 },
{ "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 }, { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 },
#endif #endif
}; };
static int bitmask_size = sizeof(Bitmask)*8; static int bitmask_size = sizeof(Bitmask)*8;

View File

@@ -43,14 +43,10 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
** To state it another way: This routine returns a list of all triggers ** 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 ** that fire off of pTab. The list will include any TEMP triggers on
** pTab as well as the triggers lised in pTab->pTrigger. ** 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){ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
Schema * const pTmpSchema = pParse->db->aDb[1].pSchema; Schema * const pTmpSchema = pParse->db->aDb[1].pSchema;
Trigger *pList = 0; /* List of triggers to return */ Trigger *pList = 0; /* List of triggers to return */
const int bOta = !!(pParse->db->flags & SQLITE_OtaMode);
if( pParse->disableTriggers ){ if( pParse->disableTriggers ){
return 0; return 0;
@@ -64,13 +60,13 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
if( pTrig->pTabSchema==pTab->pSchema if( pTrig->pTabSchema==pTab->pSchema
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName) && 0==sqlite3StrICmp(pTrig->table, pTab->zName)
){ ){
pTrig->pNext = ((pList || bOta) ? pList : pTab->pTrigger); pTrig->pNext = (pList ? pList : pTab->pTrigger);
pList = pTrig; pList = pTrig;
} }
} }
} }
return ((pList || bOta) ? pList : pTab->pTrigger); return (pList ? pList : pTab->pTrigger);
} }
/* /*

View File

@@ -467,183 +467,4 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
return rc; 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; i<pIdx->nColumn; i++){
const char *zColl = 0;
if( i<pIdx->nKeyCol ){
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; i<pIdx->nColumn; i++){
const char *zColl = 0;
int nColl;
int iCol = pTbl->iPKey;
if( i<pIdx->nKeyCol ){
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 */ #endif /* #ifndef SQLITE_OMIT_INCRBLOB */

View File

@@ -318,11 +318,6 @@ set pragma_def {
NAME: pager_ota_mode NAME: pager_ota_mode
IF: defined(SQLITE_ENABLE_OTA) IF: defined(SQLITE_ENABLE_OTA)
NAME: ota_mode
TYPE: FLAG
ARG: SQLITE_OtaMode
IF: defined(SQLITE_ENABLE_OTA)
} }
fconfigure stdout -translation lf fconfigure stdout -translation lf
set name {} set name {}