ota1 close
return $filename
}
+#
+# Create a simple OTA database. That expects to write to a table:
+#
+# CREATE TABLE t1(c, b, '(a)' INTEGER PRIMARY KEY);
+#
+# This OTA includes both insert and delete operations.
+#
+proc create_ota4b {filename} {
+ forcedelete $filename
+ sqlite3 ota1 $filename
+ ota1 eval {
+ CREATE TABLE data_t1(c, b, '(a)', ota_control);
+ INSERT INTO data_t1 VALUES(3, 2, 1, 0);
+ INSERT INTO data_t1 VALUES(5, NULL, 2, 1);
+ INSERT INTO data_t1 VALUES(9, 8, 3, 0);
+ INSERT INTO data_t1 VALUES(11, NULL, 4, 1);
+ }
+ ota1 close
+ return $filename
+}
# Create a simple OTA database. That expects to write to a table:
#
}
}
+ foreach {tn2 cmd} {1 run_ota 2 step_ota} {
+ foreach {tn schema} {
+ 1 {
+ CREATE TABLE t1(c, b, '(a)' INTEGER PRIMARY KEY);
+ CREATE INDEX i1 ON t1(c, b);
+ }
+ 2 {
+ CREATE TABLE t1(c, b, '(a)' PRIMARY KEY);
+ }
+ 3 {
+ CREATE TABLE t1(c, b, '(a)' PRIMARY KEY) WITHOUT ROWID;
+ }
+ } {
+ reset_db
+ execsql $schema
+ execsql {
+ INSERT INTO t1('(a)', b, c) VALUES(2, 'hello', 'world');
+ INSERT INTO t1('(a)', b, c) VALUES(4, 'hello', 'planet');
+ INSERT INTO t1('(a)', b, c) VALUES(6, 'hello', 'xyz');
+ }
+
+ do_test $tn3.4.$tn2.$tn.1 {
+ create_ota4b ota.db
+ $cmd test.db ota.db
+ } {SQLITE_DONE}
+
+ do_execsql_test $tn3.4.$tn2.$tn.2 {
+ SELECT * FROM t1 ORDER BY "(a)" ASC;
+ } {
+ 3 2 1
+ 9 8 3
+ xyz hello 6
+ }
+
+ do_execsql_test $tn3.4.$tn2.$tn.3 { PRAGMA integrity_check } ok
+ }
+ }
+
#-------------------------------------------------------------------------
#
foreach {tn2 cmd} {1 run_ota 2 step_ota} {
# * A no-PK table with no ota_rowid column.
# * A PK table with an ota_rowid column.
#
+ # 6: An update string of the wrong length
+ #
ifcapable fts3 {
foreach {tn schema error} {
1 {
CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
CREATE TABLE ota.data_t1(a, b, ota_rowid, ota_control);
} {SQLITE_ERROR - table data_t1 may not have ota_rowid column}
+
+ 6 {
+ CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
+ CREATE TABLE ota.data_t1(a, b, ota_control);
+ INSERT INTO ota.data_t1 VALUES(1, 2, 'x.x');
+ } {SQLITE_ERROR - invalid ota_control value}
} {
reset_db
file exists test.db-wal
} {1}
-breakpoint
do_test 2.3 {
sqlite3ota ota test.db ota.db
ota step
list [catch {ota close} msg] $msg
} {1 {SQLITE_ERROR - cannot update wal mode database}}
+#--------------------------------------------------------------------
+# Test a constraint violation message with an unusual table name.
+# Specifically, one for which the first character is a codepoint
+# smaller than 30 (character '0').
+#
+reset_db
+do_execsql_test 3.1 {
+ CREATE TABLE "(t1)"(a PRIMARY KEY, b, c);
+ INSERT INTO "(t1)" VALUES(1, 2, 3);
+ INSERT INTO "(t1)" VALUES(4, 5, 6);
+}
+db close
+
+do_test 3.2 {
+ forcedelete ota.db
+ sqlite3 dbo ota.db
+ dbo eval {
+ CREATE TABLE "data_(t1)"(a, b, c, ota_control);
+ INSERT INTO "data_(t1)" VALUES(4, 8, 9, 0);
+ }
+ dbo close
+
+ sqlite3ota ota test.db ota.db
+ ota step
+ ota step
+} {SQLITE_CONSTRAINT}
+
+do_test 3.3 {
+ list [catch {ota close} msg] $msg
+} {1 {SQLITE_CONSTRAINT - UNIQUE constraint failed: (t1).a}}
+
+#--------------------------------------------------------------------
+# Check that once an OTA update has been applied, attempting to apply
+# it a second time is a no-op (as the state stored in the OTA database is
+# "all steps completed").
+#
+reset_db
+do_execsql_test 4.1 {
+ CREATE TABLE "(t1)"(a, b, c, PRIMARY KEY(c, b, a));
+ INSERT INTO "(t1)" VALUES(1, 2, 3);
+ INSERT INTO "(t1)" VALUES(4, 5, 6);
+}
+db close
+
+do_test 4.2 {
+ forcedelete ota.db
+ sqlite3 dbo ota.db
+ dbo eval {
+ CREATE TABLE "data_(t1)"(a, b, c, ota_control);
+ INSERT INTO "data_(t1)" VALUES(7, 8, 9, 0);
+ INSERT INTO "data_(t1)" VALUES(1, 2, 3, 1);
+ }
+ dbo close
+
+ sqlite3ota ota test.db ota.db
+ while {[ota step]=="SQLITE_OK"} { }
+ ota close
+} {SQLITE_DONE}
+
+do_test 4.3 {
+ sqlite3ota ota test.db ota.db
+ ota step
+} {SQLITE_DONE}
+
+do_test 4.4 {
+ ota close
+} {SQLITE_DONE}
+
+# Also, check that an invalid state value in the ota_state table is
+# detected and reported as corruption.
+do_test 4.5 {
+ sqlite3 dbo ota.db
+ dbo eval { UPDATE ota_state SET v = -1 WHERE k = 1 }
+ dbo close
+ sqlite3ota ota test.db ota.db
+ ota step
+} {SQLITE_CORRUPT}
+do_test 4.6 {
+ list [catch {ota close} msg] $msg
+} {1 SQLITE_CORRUPT}
+
finish_test
do_test 1.1 {
forcedelete ota.db
execsql {
+ PRAGMA encoding = utf16;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX t1cb ON t1(c, b);
INSERT INTO t1 VALUES(1, 1, 1);
forcecopy ota.db ota.db.bak
} {}
-do_faultsim_test 2 -faults oom-trans* -prep {
- catch { db close }
- forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal
- forcecopy test.db.bak test.db
- forcecopy ota.db.bak ota.db
-} -body {
- sqlite3ota ota test.db ota.db
- while {[ota step]=="SQLITE_OK"} {}
- ota close
-} -test {
- faultsim_test_result {0 SQLITE_DONE} \
- {1 {SQLITE_NOMEM - out of memory}} \
- {1 SQLITE_NOMEM} \
- {1 SQLITE_IOERR_NOMEM} \
- {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}}
- if {$testrc==0} {
- sqlite3 db test.db
- faultsim_integrity_check
- set res [db eval {
- SELECT * FROM t1 UNION ALL SELECT * FROM t2;
- }]
- set expected [list {*}{
- 1 1 1 3 three 3 4 4 4
- a a a c see c d d d
- }]
-
- if {$res != $expected} {
- puts ""
- puts "res: $res"
- puts "exp: $expected"
- error "data not as expected!"
+sqlite3_shutdown
+set lookaside_config [sqlite3_config_lookaside 0 0]
+sqlite3_initialize
+autoinstall_test_functions
+
+foreach {tn f reslist} {
+ 1 oom-tra* {
+ {0 SQLITE_DONE}
+ {1 {SQLITE_NOMEM - out of memory}}
+ {1 SQLITE_NOMEM}
+ {1 SQLITE_IOERR_NOMEM}
+ {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}}
+ }
+ 2 ioerr-* {
+ {0 SQLITE_DONE}
+ {1 {SQLITE_IOERR - disk I/O error}}
+ {1 SQLITE_IOERR}
+ {1 SQLITE_IOERR_WRITE}
+ {1 SQLITE_IOERR_READ}
+ {1 SQLITE_IOERR_FSYNC}
+ {1 {SQLITE_ERROR - SQL logic error or missing database}}
+ {1 {SQLITE_ERROR - unable to open database: ota.db}}
+ {1 {SQLITE_IOERR - unable to open database: ota.db}}
+ }
+} {
+ do_faultsim_test 2 -faults $::f -prep {
+ catch { db close }
+ forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal
+ forcecopy test.db.bak test.db
+ forcecopy ota.db.bak ota.db
+ } -body {
+ sqlite3ota ota test.db ota.db
+ while {[ota step]=="SQLITE_OK"} {}
+ ota close
+ } -test {
+ faultsim_test_result {*}$::reslist
+ if {$testrc==0} {
+ sqlite3 db test.db
+ faultsim_integrity_check
+ set res [db eval {
+ SELECT * FROM t1 UNION ALL SELECT * FROM t2;
+ }]
+ set expected [list {*}{
+ 1 1 1 3 three 3 4 4 4
+ a a a c see c d d d
+ }]
+
+ if {$res != $expected} {
+ puts ""
+ puts "res: $res"
+ puts "exp: $expected"
+ error "data not as expected!"
+ }
}
}
}
+catch {db close}
+sqlite3_shutdown
+sqlite3_config_lookaside {*}$lookaside_config
+sqlite3_initialize
+autoinstall_test_functions
+
proc copy_if_exists {src target} {
if {[file exists $src]} {
forcecopy $src $target
}else{
pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0);
pIter->iTnum = sqlite3_column_int(pIter->pTblIter, 1);
- rc = SQLITE_OK;
+ rc = pIter->zTbl ? SQLITE_OK : SQLITE_NOMEM;
}
}else{
if( pIter->zIdx==0 ){
- sqlite3_bind_text(pIter->pIdxIter, 1, pIter->zTbl, -1, SQLITE_STATIC);
+ sqlite3_stmt *pIdx = pIter->pIdxIter;
+ rc = sqlite3_bind_text(pIdx, 1, pIter->zTbl, -1, SQLITE_STATIC);
}
- rc = sqlite3_step(pIter->pIdxIter);
- if( rc!=SQLITE_ROW ){
- rc = sqlite3_reset(pIter->pIdxIter);
- pIter->bCleanup = 1;
- pIter->zIdx = 0;
- }else{
- pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0);
- pIter->iTnum = sqlite3_column_int(pIter->pIdxIter, 1);
- pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2);
- rc = SQLITE_OK;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_step(pIter->pIdxIter);
+ if( rc!=SQLITE_ROW ){
+ rc = sqlite3_reset(pIter->pIdxIter);
+ pIter->bCleanup = 1;
+ pIter->zIdx = 0;
+ }else{
+ pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0);
+ pIter->iTnum = sqlite3_column_int(pIter->pIdxIter, 1);
+ pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2);
+ rc = pIter->zIdx ? SQLITE_OK : SQLITE_NOMEM;
+ }
}
}
}
}
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
+ if( zName==0 ) break; /* An OOM - finalize() below returns S_NOMEM */
for(i=iOrder; i<pIter->nTblCol; i++){
if( 0==strcmp(zName, pIter->azTblCol[i]) ) break;
}
** its name. Otherwise, use "ota_rowid". */
if( pIter->eType==OTA_PK_IPK ){
int i;
- for(i=0; i<pIter->nTblCol && pIter->abTblPk[i]==0; i++);
+ for(i=0; pIter->abTblPk[i]==0; i++);
assert( i<pIter->nTblCol );
zCol = pIter->azTblCol[i];
}else{
*/
static void otaBadControlError(sqlite3ota *p){
p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("Invalid ota_control value");
+ p->zErrmsg = sqlite3_mprintf("invalid ota_control value");
}
);
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXList) ){
const char *zOrig = (const char*)sqlite3_column_text(pXList,3);
- if( zOrig && strcmp(zOrig,"pk")==0 ){
- p->rc = prepareFreeAndCollectError(p->db, &pXInfo, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.index_xinfo = %Q",
- sqlite3_column_text(pXList,1))
- );
+ if( zOrig && strcmp(zOrig, "pk")==0 ){
+ const char *zIdx = (const char*)sqlite3_column_text(pXList,1);
+ if( zIdx ){
+ p->rc = prepareFreeAndCollectError(p->db, &pXInfo, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
+ );
+ }
break;
}
}
- sqlite3_finalize(pXList);
+ rc = sqlite3_finalize(pXList);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
+
while( p->rc==SQLITE_OK && pXInfo && SQLITE_ROW==sqlite3_step(pXInfo) ){
if( sqlite3_column_int(pXInfo, 5) ){
/* int iCid = sqlite3_column_int(pXInfo, 0); */
}
}
z = otaMPrintf(p, "%z)", z);
-
rc = sqlite3_finalize(pXInfo);
if( p->rc==SQLITE_OK ) p->rc = rc;
}
break;
}
- case SQLITE_TEXT:
- *pzMask = (const char*)sqlite3_column_text(p->objiter.pSelect, iCol);
+ case SQLITE_TEXT: {
+ const unsigned char *z = sqlite3_column_text(p->objiter.pSelect, iCol);
+ if( z==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ *pzMask = (const char*)z;
+ }
res = OTA_UPDATE;
+
break;
+ }
default:
break;
}
pVal = sqlite3_column_value(pIter->pSelect, i);
- sqlite3_bind_value(pWriter, i+1, pVal);
+ p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
+ if( p->rc==SQLITE_RANGE ) p->rc = SQLITE_OK;
+ if( p->rc ) goto step_out;
}
if( pIter->zIdx==0
&& (pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE)
*/
assertColumnName(pIter->pSelect, pIter->nCol+1, "ota_rowid");
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
- sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
+ p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_step(pWriter);
+ p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
}
- sqlite3_step(pWriter);
- p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
}else if( eType==OTA_UPDATE ){
sqlite3_value *pVal;
sqlite3_stmt *pUpdate = 0;
otaGetUpdateStmt(p, pIter, zMask, &pUpdate);
if( pUpdate ){
for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
+ char c = zMask[pIter->aiSrcOrder[i]];
pVal = sqlite3_column_value(pIter->pSelect, i);
- sqlite3_bind_value(pUpdate, i+1, pVal);
+ if( pIter->abTblPk[i] || c=='x' || c=='d' ){
+ p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
+ }
}
- if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){
+ if( p->rc==SQLITE_OK
+ && (pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE)
+ ){
/* Bind the ota_rowid value to column _rowid_ */
assertColumnName(pIter->pSelect, pIter->nCol+1, "ota_rowid");
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
- sqlite3_bind_value(pUpdate, pIter->nCol+1, pVal);
+ p->rc = sqlite3_bind_value(pUpdate, pIter->nCol+1, pVal);
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_step(pUpdate);
+ p->rc = resetAndCollectError(pUpdate, &p->zErrmsg);
}
- sqlite3_step(pUpdate);
- p->rc = resetAndCollectError(pUpdate, &p->zErrmsg);
}
}else{
/* no-op */
p->rc = sqlite3_exec(p->db, OTA_CREATE_STATE, 0, 0, &p->zErrmsg);
}
- /* Check that this is not a wal mode database. If it is, it cannot be
- ** updated. There is also a check for a live *-wal file in otaVfsAccess()
- ** function, on the off chance that the target is a wal database for
- ** which the first page of the db file has been overwritten by garbage
- ** during an earlier failed checkpoint. */
-#if 0
- if( p->rc==SQLITE_OK && p->pTargetFd->iWriteVer>1 ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
- }
-#endif
-
if( p->rc==SQLITE_OK ){
pState = otaLoadState(p);
assert( pState || p->rc!=SQLITE_OK );
if( p->rc==SQLITE_OK ){
if( p->eStage==OTA_STAGE_OAL ){
+
+ /* Check that this is not a wal mode database. If it is, it cannot
+ ** be updated. */
if( p->pTargetFd->pWalFd ){
p->rc = SQLITE_ERROR;
p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
p->nStep = pState->nRow;
}else if( p->eStage==OTA_STAGE_DONE ){
p->rc = SQLITE_DONE;
+ }else{
+ p->rc = SQLITE_CORRUPT;
}
}
ota_file *p = (ota_file*)pFile;
int rc;
- if( p->pOta
- && p->pOta->eStage==OTA_STAGE_CAPTURE
- && (p->openFlags & SQLITE_OPEN_WAL)
- ){
+ if( p->pOta && p->pOta->eStage==OTA_STAGE_CAPTURE ){
+ assert( p->openFlags & SQLITE_OPEN_WAL );
rc = otaCaptureWalRead(p->pOta, iOfst, iAmt);
}else{
rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
){
ota_file *p = (ota_file*)pFile;
int rc;
- if( p->pOta
- && p->pOta->eStage==OTA_STAGE_CAPTURE
- && (p->openFlags & SQLITE_OPEN_MAIN_DB)
- ){
+ if( p->pOta && p->pOta->eStage==OTA_STAGE_CAPTURE ){
+ assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
rc = otaCaptureDbWrite(p->pOta, iOfst);
}else{
rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
-C Add\sfurther\stests\sand\sfixes\sfor\sota.
-D 2015-02-16T11:48:34.819
+C Add\sextra\stests\sand\sfixes\sfor\sota.
+D 2015-02-16T21:13:19.665
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 6b9e7677829aa94b9f30949656e27312aefb9a46
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
F ext/ota/README.txt 2ce4ffbb0aaa6731b041c27a7359f9a5f1c69152
F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91
-F ext/ota/ota1.test dee5b852353642a243e0bf414d332b1bccd5324f
+F ext/ota/ota1.test 88a47987dc12780c23d9efbeb0e9416c838eb1f6
F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
-F ext/ota/ota11.test 44e9ebdc1d9c23214c739f122f2b36e169e515aa
+F ext/ota/ota11.test 0a0c56b9474f82097018a8f399172417737c64c9
F ext/ota/ota3.test cd654ef16fc6b3d3596894ee3f3b8fd821b969f5
F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
F ext/ota/ota6.test 40996b7716dee72a6c5d28c3bee436717a438d3d
F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b
F ext/ota/otaA.test ef4bfa8cfd4ed814ae86f7457b64aa2f18c90171
-F ext/ota/otafault.test 508ba87c83d632670ac0f94371a465d4bb4d49dd
-F ext/ota/sqlite3ota.c f2ea3fe9d7fceec5efc1ad62b8bf07ec607f99c5
+F ext/ota/otafault.test fd3d4d9b9ed3cbe4461cde602e40f50825e0ee2a
+F ext/ota/sqlite3ota.c f378ebb435ce79bb5060907c3bc994c5b48cbb85
F ext/ota/sqlite3ota.h 1cc7201086fe65a36957740381485a24738c4077
F ext/ota/test_ota.c 5dd58e4e6eb3ae7b471566616d44b701971bce88
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P f20779a6e890ba73bfaa904cefcf3a029b01fed4
-R d9098c0831f1564055344cfb128a3e0f
+P 62dc1fffc38cb157c15105098749b6dd0198eb84
+R 26fc1fcf1b321dc2a4f4bbbaf0fa84e9
U dan
-Z f0ac85428b81638540d3d3b58c8f458b
+Z bb700675d8726f14df483f7f803a4d01
-62dc1fffc38cb157c15105098749b6dd0198eb84
\ No newline at end of file
+e0b7151962fedbcac975f2216fd6b33b995a8945
\ No newline at end of file