/ Check-in [69a49318]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 69a493182fd77bec91598516ee42c11a6db1d039
User & Date: drh 2010-02-24 19:23:56
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: 46f406b2 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: dd480f62 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: 69a49318 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: a8c984c1 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vacuum.c.

    14     14   ** Most of the code in this file may be omitted by defining the
    15     15   ** SQLITE_OMIT_VACUUM macro.
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   #include "vdbeInt.h"
    19     19   
    20     20   #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
           21  +/*
           22  +** Finalize a prepared statement.  If there was an error, store the
           23  +** text of the error message in *pzErrMsg.  Return the result code.
           24  +*/
           25  +static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
           26  +  int rc;
           27  +  rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
           28  +  if( rc ){
           29  +    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
           30  +  }
           31  +  return rc;
           32  +}
           33  +
    21     34   /*
    22     35   ** Execute zSql on database db. Return an error code.
    23     36   */
    24         -static int execSql(sqlite3 *db, const char *zSql){
           37  +static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    25     38     sqlite3_stmt *pStmt;
    26     39     VVA_ONLY( int rc; )
    27     40     if( !zSql ){
    28     41       return SQLITE_NOMEM;
    29     42     }
    30     43     if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
           44  +    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
    31     45       return sqlite3_errcode(db);
    32     46     }
    33     47     VVA_ONLY( rc = ) sqlite3_step(pStmt);
    34     48     assert( rc!=SQLITE_ROW );
    35         -  return sqlite3_finalize(pStmt);
           49  +  return vacuumFinalize(db, pStmt, pzErrMsg);
    36     50   }
    37     51   
    38     52   /*
    39     53   ** Execute zSql on database db. The statement returns exactly
    40     54   ** one column. Execute this as SQL on the same database.
    41     55   */
    42         -static int execExecSql(sqlite3 *db, const char *zSql){
           56  +static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    43     57     sqlite3_stmt *pStmt;
    44     58     int rc;
    45     59   
    46     60     rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    47     61     if( rc!=SQLITE_OK ) return rc;
    48     62   
    49     63     while( SQLITE_ROW==sqlite3_step(pStmt) ){
    50         -    rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
           64  +    rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
    51     65       if( rc!=SQLITE_OK ){
    52         -      sqlite3_finalize(pStmt);
           66  +      vacuumFinalize(db, pStmt, pzErrMsg);
    53     67         return rc;
    54     68       }
    55     69     }
    56     70   
    57         -  return sqlite3_finalize(pStmt);
           71  +  return vacuumFinalize(db, pStmt, pzErrMsg);
    58     72   }
    59     73   
    60     74   /*
    61     75   ** The non-standard VACUUM command is used to clean up the database,
    62     76   ** collapse free space, etc.  It is modelled after the VACUUM command
    63     77   ** in PostgreSQL.
    64     78   **
................................................................................
   121    135     ** that actually made the VACUUM run slower.  Very little journalling
   122    136     ** actually occurs when doing a vacuum since the vacuum_db is initially
   123    137     ** empty.  Only the journal header is written.  Apparently it takes more
   124    138     ** time to parse and run the PRAGMA to turn journalling off than it does
   125    139     ** to write the journal header file.
   126    140     */
   127    141     zSql = "ATTACH '' AS vacuum_db;";
   128         -  rc = execSql(db, zSql);
          142  +  rc = execSql(db, pzErrMsg, zSql);
   129    143     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   130    144     pDb = &db->aDb[db->nDb-1];
   131    145     assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
   132    146     pTemp = db->aDb[db->nDb-1].pBt;
   133    147   
   134    148     /* The call to execSql() to attach the temp database has left the file
   135    149     ** locked (as there was more than one active statement when the transaction
................................................................................
   153    167     if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
   154    168      || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
   155    169      || NEVER(db->mallocFailed)
   156    170     ){
   157    171       rc = SQLITE_NOMEM;
   158    172       goto end_of_vacuum;
   159    173     }
   160         -  rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
          174  +  rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
   161    175     if( rc!=SQLITE_OK ){
   162    176       goto end_of_vacuum;
   163    177     }
   164    178   
   165    179   #ifndef SQLITE_OMIT_AUTOVACUUM
   166    180     sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
   167    181                                              sqlite3BtreeGetAutoVacuum(pMain));
   168    182   #endif
   169    183   
   170    184     /* Begin a transaction */
   171         -  rc = execSql(db, "BEGIN EXCLUSIVE;");
          185  +  rc = execSql(db, pzErrMsg, "BEGIN EXCLUSIVE;");
   172    186     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   173    187   
   174    188     /* Query the schema of the main database. Create a mirror schema
   175    189     ** in the temporary database.
   176    190     */
   177         -  rc = execExecSql(db, 
          191  +  rc = execExecSql(db, pzErrMsg,
   178    192         "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
   179    193         "  FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
   180    194         "   AND rootpage>0"
   181    195     );
   182    196     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   183         -  rc = execExecSql(db, 
          197  +  rc = execExecSql(db, pzErrMsg,
   184    198         "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
   185    199         "  FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
   186    200     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   187         -  rc = execExecSql(db, 
          201  +  rc = execExecSql(db, pzErrMsg,
   188    202         "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
   189    203         "  FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
   190    204     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   191    205   
   192    206     /* Loop through the tables in the main database. For each, do
   193    207     ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
   194    208     ** the contents to the temporary database.
   195    209     */
   196         -  rc = execExecSql(db, 
          210  +  rc = execExecSql(db, pzErrMsg,
   197    211         "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
   198    212         "|| ' SELECT * FROM main.' || quote(name) || ';'"
   199    213         "FROM main.sqlite_master "
   200    214         "WHERE type = 'table' AND name!='sqlite_sequence' "
   201    215         "  AND rootpage>0"
   202         -
   203    216     );
   204    217     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   205    218   
   206    219     /* Copy over the sequence table
   207    220     */
   208         -  rc = execExecSql(db, 
          221  +  rc = execExecSql(db, pzErrMsg,
   209    222         "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
   210    223         "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
   211    224     );
   212    225     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   213         -  rc = execExecSql(db, 
          226  +  rc = execExecSql(db, pzErrMsg,
   214    227         "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
   215    228         "|| ' SELECT * FROM main.' || quote(name) || ';' "
   216    229         "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
   217    230     );
   218    231     if( rc!=SQLITE_OK ) goto end_of_vacuum;
   219    232   
   220    233   
   221    234     /* Copy the triggers, views, and virtual tables from the main database
   222    235     ** over to the temporary database.  None of these objects has any
   223    236     ** associated storage, so all we have to do is copy their entries
   224    237     ** from the SQLITE_MASTER table.
   225    238     */
   226         -  rc = execSql(db,
          239  +  rc = execSql(db, pzErrMsg,
   227    240         "INSERT INTO vacuum_db.sqlite_master "
   228    241         "  SELECT type, name, tbl_name, rootpage, sql"
   229    242         "    FROM main.sqlite_master"
   230    243         "   WHERE type='view' OR type='trigger'"
   231    244         "      OR (type='table' AND rootpage=0)"
   232    245     );
   233    246     if( rc ) goto end_of_vacuum;

Changes to src/vdbe.c.

   846    846     p->rc = pOp->p1;
   847    847     p->errorAction = (u8)pOp->p2;
   848    848     p->pc = pc;
   849    849     if( pOp->p4.z ){
   850    850       assert( p->rc!=SQLITE_OK );
   851    851       sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z);
   852    852       sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pc, p->zSql, pOp->p4.z);
          853  +  }else if( p->rc ){
          854  +    sqlite3_log(pOp->p1, "constraint failed at %d in [%s]", pc, p->zSql);
   853    855     }
   854    856     rc = sqlite3VdbeHalt(p);
   855    857     assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
   856    858     if( rc==SQLITE_BUSY ){
   857    859       p->rc = rc = SQLITE_BUSY;
   858    860     }else{
   859    861       assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT );

Changes to test/analyze3.test.

   477    477     sqlite3_step $S
   478    478   } {SQLITE_DONE}
   479    479   do_test analyze3-4.1.2 {
   480    480     sqlite3_reset $S
   481    481     sqlite3_bind_text $S 2 "abc" 3
   482    482     execsql { DROP TABLE t1 }
   483    483     sqlite3_step $S
   484         -} {SQLITE_SCHEMA}
          484  +} {SQLITE_ERROR}
   485    485   do_test analyze3-4.1.3 {
   486    486     sqlite3_finalize $S
   487         -} {SQLITE_SCHEMA}
          487  +} {SQLITE_ERROR}
   488    488   
   489    489   # Check an authorization error.
   490    490   #
   491    491   do_test analyze3-4.2.1 {
   492    492     execsql {
   493    493       BEGIN;
   494    494       CREATE TABLE t1(a, b, c);
................................................................................
   507    507     if {[lindex $args 0] == "SQLITE_READ"} {return SQLITE_DENY}
   508    508     return SQLITE_OK
   509    509   }
   510    510   do_test analyze3-4.2.2 {
   511    511     sqlite3_reset $S
   512    512     sqlite3_bind_text $S 2 "abc" 3
   513    513     sqlite3_step $S
   514         -} {SQLITE_SCHEMA}
          514  +} {SQLITE_AUTH}
   515    515   do_test analyze3-4.2.4 {
   516    516     sqlite3_finalize $S
   517         -} {SQLITE_SCHEMA}
          517  +} {SQLITE_AUTH}
   518    518   
   519    519   # Check the effect of an authorization error that occurs in a re-prepare
   520    520   # performed by sqlite3_step() is the same as one that occurs within
   521    521   # sqlite3Reprepare().
   522    522   #
   523    523   do_test analyze3-4.3.1 {
   524    524     db auth {}
   525    525     set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy]
   526    526     execsql { CREATE TABLE t2(d, e, f) }
   527    527     db auth auth
   528    528     sqlite3_step $S
   529         -} {SQLITE_SCHEMA}
          529  +} {SQLITE_AUTH}
   530    530   do_test analyze3-4.3.2 {
   531    531     sqlite3_finalize $S
   532         -} {SQLITE_SCHEMA}
          532  +} {SQLITE_AUTH}
   533    533   db auth {}
   534    534   
   535    535   #-------------------------------------------------------------------------
   536    536   # Test that modifying bound variables using the clear_bindings() or
   537    537   # transfer_bindings() APIs works.
   538    538   #
   539    539   #   analyze3-5.1.*: sqlite3_clear_bindings()