Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add a sqlite3_log() call on anonymous constraint failures. Fix the output of test cases having to do with improved reprepare reporting. Fix the VACUUM command to report more helpful error messages when things go wrong. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
69a493182fd77bec91598516ee42c11a |
User & Date: | drh 2010-02-24 19:23:56.000 |
References
2010-02-25
| ||
02:32 | Merge in all of the logging enhancements. This is a cherrypick merge of the following check-ins: [103321e37a], [a8076aede3], [6d910245ad], [7c4cca6d1a], [edea3bb740], [1a6d4bb130], [a8c984c1d6], [69a493182f], and [1168763d2c]. (check-in: 46f406b202 user: drh tags: branch-3.6.22) | |
Context
2010-02-24
| ||
19:36 | Changes to compile time option diags to report values for some defines. Added test cases to TCL test suite (ctime.test). (check-in: dd480f62af user: shaneh tags: trunk) | |
19:23 | Add a sqlite3_log() call on anonymous constraint failures. Fix the output of test cases having to do with improved reprepare reporting. Fix the VACUUM command to report more helpful error messages when things go wrong. (check-in: 69a493182f user: drh tags: trunk) | |
18:40 | Fix an incorrect ALWAYS() macro in vdbeapi.c. Fix the output of a few test cases that changed due to better error propagation out of reprepare. (check-in: a8c984c1d6 user: drh tags: trunk) | |
Changes
Changes to src/vacuum.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 | ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. */ #include "sqliteInt.h" #include "vdbeInt.h" #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) /* ** Execute zSql on database db. Return an error code. */ | > > > > > > > > > > > > > | > | | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. */ #include "sqliteInt.h" #include "vdbeInt.h" #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) /* ** Finalize a prepared statement. If there was an error, store the ** text of the error message in *pzErrMsg. Return the result code. */ static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){ int rc; rc = sqlite3VdbeFinalize((Vdbe*)pStmt); if( rc ){ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); } return rc; } /* ** Execute zSql on database db. Return an error code. */ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ sqlite3_stmt *pStmt; VVA_ONLY( int rc; ) if( !zSql ){ return SQLITE_NOMEM; } if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); return sqlite3_errcode(db); } VVA_ONLY( rc = ) sqlite3_step(pStmt); assert( rc!=SQLITE_ROW ); return vacuumFinalize(db, pStmt, pzErrMsg); } /* ** Execute zSql on database db. The statement returns exactly ** one column. Execute this as SQL on the same database. */ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ sqlite3_stmt *pStmt; int rc; rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; while( SQLITE_ROW==sqlite3_step(pStmt) ){ rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0)); if( rc!=SQLITE_OK ){ vacuumFinalize(db, pStmt, pzErrMsg); return rc; } } return vacuumFinalize(db, pStmt, pzErrMsg); } /* ** The non-standard VACUUM command is used to clean up the database, ** collapse free space, etc. It is modelled after the VACUUM command ** in PostgreSQL. ** |
︙ | ︙ | |||
121 122 123 124 125 126 127 | ** that actually made the VACUUM run slower. Very little journalling ** actually occurs when doing a vacuum since the vacuum_db is initially ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ zSql = "ATTACH '' AS vacuum_db;"; | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | ** that actually made the VACUUM run slower. Very little journalling ** actually occurs when doing a vacuum since the vacuum_db is initially ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ zSql = "ATTACH '' AS vacuum_db;"; rc = execSql(db, pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_vacuum; pDb = &db->aDb[db->nDb-1]; assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 ); pTemp = db->aDb[db->nDb-1].pBt; /* The call to execSql() to attach the temp database has left the file ** locked (as there was more than one active statement when the transaction |
︙ | ︙ | |||
153 154 155 156 157 158 159 | if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) || NEVER(db->mallocFailed) ){ rc = SQLITE_NOMEM; goto end_of_vacuum; } | | | | | | | < | | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) || NEVER(db->mallocFailed) ){ rc = SQLITE_NOMEM; goto end_of_vacuum; } rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); if( rc!=SQLITE_OK ){ goto end_of_vacuum; } #ifndef SQLITE_OMIT_AUTOVACUUM sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac : sqlite3BtreeGetAutoVacuum(pMain)); #endif /* Begin a transaction */ rc = execSql(db, pzErrMsg, "BEGIN EXCLUSIVE;"); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ rc = execExecSql(db, pzErrMsg, "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) " " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" " AND rootpage>0" ); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execExecSql(db, pzErrMsg, "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execExecSql(db, pzErrMsg, "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Loop through the tables in the main database. For each, do ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ rc = execExecSql(db, pzErrMsg, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) || ';'" "FROM main.sqlite_master " "WHERE type = 'table' AND name!='sqlite_sequence' " " AND rootpage>0" ); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy over the sequence table */ rc = execExecSql(db, pzErrMsg, "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' " ); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execExecSql(db, pzErrMsg, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) || ';' " "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';" ); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries ** from the SQLITE_MASTER table. */ rc = execSql(db, pzErrMsg, "INSERT INTO vacuum_db.sqlite_master " " SELECT type, name, tbl_name, rootpage, sql" " FROM main.sqlite_master" " WHERE type='view' OR type='trigger'" " OR (type='table' AND rootpage=0)" ); if( rc ) goto end_of_vacuum; |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
846 847 848 849 850 851 852 853 854 855 856 857 858 859 | p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pc; if( pOp->p4.z ){ assert( p->rc!=SQLITE_OK ); sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z); sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pc, p->zSql, pOp->p4.z); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ p->rc = rc = SQLITE_BUSY; }else{ assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ); | > > | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 | p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pc; if( pOp->p4.z ){ assert( p->rc!=SQLITE_OK ); sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z); sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pc, p->zSql, pOp->p4.z); }else if( p->rc ){ sqlite3_log(pOp->p1, "constraint failed at %d in [%s]", pc, p->zSql); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ p->rc = rc = SQLITE_BUSY; }else{ assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ); |
︙ | ︙ |
Changes to test/analyze3.test.
︙ | ︙ | |||
477 478 479 480 481 482 483 | sqlite3_step $S } {SQLITE_DONE} do_test analyze3-4.1.2 { sqlite3_reset $S sqlite3_bind_text $S 2 "abc" 3 execsql { DROP TABLE t1 } sqlite3_step $S | | | | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | sqlite3_step $S } {SQLITE_DONE} do_test analyze3-4.1.2 { sqlite3_reset $S sqlite3_bind_text $S 2 "abc" 3 execsql { DROP TABLE t1 } sqlite3_step $S } {SQLITE_ERROR} do_test analyze3-4.1.3 { sqlite3_finalize $S } {SQLITE_ERROR} # Check an authorization error. # do_test analyze3-4.2.1 { execsql { BEGIN; CREATE TABLE t1(a, b, c); |
︙ | ︙ | |||
507 508 509 510 511 512 513 | if {[lindex $args 0] == "SQLITE_READ"} {return SQLITE_DENY} return SQLITE_OK } do_test analyze3-4.2.2 { sqlite3_reset $S sqlite3_bind_text $S 2 "abc" 3 sqlite3_step $S | | | | | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | if {[lindex $args 0] == "SQLITE_READ"} {return SQLITE_DENY} return SQLITE_OK } do_test analyze3-4.2.2 { sqlite3_reset $S sqlite3_bind_text $S 2 "abc" 3 sqlite3_step $S } {SQLITE_AUTH} do_test analyze3-4.2.4 { sqlite3_finalize $S } {SQLITE_AUTH} # Check the effect of an authorization error that occurs in a re-prepare # performed by sqlite3_step() is the same as one that occurs within # sqlite3Reprepare(). # do_test analyze3-4.3.1 { db auth {} set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy] execsql { CREATE TABLE t2(d, e, f) } db auth auth sqlite3_step $S } {SQLITE_AUTH} do_test analyze3-4.3.2 { sqlite3_finalize $S } {SQLITE_AUTH} db auth {} #------------------------------------------------------------------------- # Test that modifying bound variables using the clear_bindings() or # transfer_bindings() APIs works. # # analyze3-5.1.*: sqlite3_clear_bindings() |
︙ | ︙ |