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:
@@ -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);
|
||||
}
|
||||
|
||||
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}}
|
||||
} {1 {SQLITE_MISMATCH - datatype mismatch}}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
do_execsql_test 2.1.2 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
} {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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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,7 +294,17 @@ 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( rc==SQLITE_OK ){
|
||||
if( pIter->bCleanup ){
|
||||
otaObjIterFreeCols(pIter);
|
||||
pIter->bCleanup = 0;
|
||||
@@ -295,6 +314,7 @@ static int otaObjIterNext(sqlite3ota *p, OtaObjIter *pIter){
|
||||
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{
|
||||
@@ -314,6 +334,7 @@ static int otaObjIterNext(sqlite3ota *p, OtaObjIter *pIter){
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
otaObjIterFinalize(pIter);
|
||||
@@ -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; 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
|
||||
** 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
assert( p->rc==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 && i<nCol; i++){
|
||||
const char *zName = (const char*)sqlite3_column_name(pStmt, i);
|
||||
if( sqlite3_strnicmp("ota_", zName, 4) ){
|
||||
char *zCopy = otaQuoteName(zName);
|
||||
char *zCopy = otaStrndup(zName, -1, &p->rc);
|
||||
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; i<pIter->nTblCol; 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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
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;
|
||||
@@ -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<nCol; i++){
|
||||
int iCol = aiCol ? aiCol[i] : i;
|
||||
char *zCol = (iCol>=0 ? pIter->azTblCol[iCol] : "ota_rowid");
|
||||
zList = sqlite3_mprintf("%z%s%s", zList, zSep, zCol);
|
||||
if( zList && azCollate ){
|
||||
zList = sqlite3_mprintf("%z COLLATE %Q", zList, azCollate[i]);
|
||||
}
|
||||
for(i=0; i<pIter->nTblCol; i++){
|
||||
const char *z = pIter->azTblCol[i];
|
||||
zList = otaMPrintfAndCollectError(p, "%z%s\"%w\"", zList, zSep, z);
|
||||
zSep = ", ";
|
||||
if( zList==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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; i<pIter->nTblCol && pIter->abTblPk[i]==0; i++);
|
||||
assert( i<pIter->nTblCol );
|
||||
@@ -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; 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 = ", ";
|
||||
if( zList==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
@@ -831,7 +756,6 @@ 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{
|
||||
@@ -841,13 +765,12 @@ static char *otaObjIterGetWhere(
|
||||
if( pIter->abTblPk[i] ){
|
||||
const char *zCol = pIter->azTblCol[i];
|
||||
zList = otaMPrintfAndCollectError(
|
||||
p, "%z%s%s=?%d", zList, zSep, zCol, i+1
|
||||
p, "%z%s\"%w\"=?%d", zList, zSep, zCol, i+1
|
||||
);
|
||||
zSep = " AND ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return zList;
|
||||
}
|
||||
|
||||
@@ -880,13 +803,14 @@ static char *otaObjIterGetSetlist(
|
||||
for(i=0; i<pIter->nTblCol; 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 && 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
|
||||
** 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; 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 ){
|
||||
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;
|
||||
}
|
||||
|
||||
|
38
manifest
38
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
|
||||
|
@@ -1 +1 @@
|
||||
cdaeab467f6aa3217be161377a9b78a4eec37093
|
||||
1c111447a07687c30ed4ad5a6c27a169c85b7ea6
|
@@ -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;
|
||||
|
@@ -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){
|
||||
|
13
src/insert.c
13
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);
|
||||
|
39
src/main.c
39
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 */
|
||||
|
13
src/pragma.c
13
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);
|
||||
|
@@ -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.
|
||||
**
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
179
src/vdbeblob.c
179
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; 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 */
|
||||
|
@@ -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 {}
|
||||
|
Reference in New Issue
Block a user