/ Check-in [c8a7b725]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Better detection and reporting of errors when initializing from the sqlite_master table. (CVS 688)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:c8a7b725b7cec792d2148455a4cecbce9dfebe80
User & Date: drh 2002-07-19 17:46:39
Context
2002-07-19
18:13
Add static ident strings (such as picked up by the RCS "ident" command) containing the library version number. (CVS 689) check-in: 712ee391 user: drh tags: trunk
17:46
Better detection and reporting of errors when initializing from the sqlite_master table. (CVS 688) check-in: c8a7b725 user: drh tags: trunk
2002-07-18
11:10
Version 2.6.0 Release 2 (CVS 687) check-in: cc4f824b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/main.c.

    10     10   **
    11     11   *************************************************************************
    12     12   ** Main file for the SQLite library.  The routines in this file
    13     13   ** implement the programmer interface to the library.  Routines in
    14     14   ** other files are for internal use by SQLite and should not be
    15     15   ** accessed by users of the library.
    16     16   **
    17         -** $Id: main.c,v 1.88 2002/07/18 01:27:18 drh Exp $
           17  +** $Id: main.c,v 1.89 2002/07/19 17:46:39 drh Exp $
    18     18   */
    19     19   #include "sqliteInt.h"
    20     20   #include "os.h"
    21     21   #include <ctype.h>
           22  +
           23  +/*
           24  +** A pointer to this structure is used to communicate information
           25  +** from sqliteInit into the sqliteInitCallback.
           26  +*/
           27  +typedef struct {
           28  +  sqlite *db;         /* The database being initialized */
           29  +  char **pzErrMsg;    /* Error message stored here */
           30  +} InitData;
           31  +
    22     32   
    23     33   /*
    24     34   ** This is the callback routine for the code that initializes the
    25     35   ** database.  See sqliteInit() below for additional information.
    26     36   **
    27     37   ** Each callback contains the following information:
    28     38   **
................................................................................
    29     39   **     argv[0] = "file-format" or "schema-cookie" or "table" or "index"
    30     40   **     argv[1] = table or index name or meta statement type.
    31     41   **     argv[2] = root page number for table or index.  NULL for meta.
    32     42   **     argv[3] = SQL create statement for the table or index
    33     43   **     argv[4] = "1" for temporary files, "0" for main database
    34     44   **
    35     45   */
    36         -int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
    37         -  sqlite *db = (sqlite*)pDb;
           46  +static
           47  +int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
           48  +  InitData *pData = (InitData*)pInit;
    38     49     Parse sParse;
    39     50     int nErr = 0;
    40     51   
    41     52     /* TODO: Do some validity checks on all fields.  In particular,
    42     53     ** make sure fields do not contain NULLs. Otherwise we might core
    43     54     ** when attempting to initialize from a corrupt database file. */
    44     55   
................................................................................
    50     61         if( argv[3] && argv[3][0] ){
    51     62           /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
    52     63           ** But because sParse.initFlag is set to 1, no VDBE code is generated
    53     64           ** or executed.  All the parser does is build the internal data
    54     65           ** structures that describe the table, index, or view.
    55     66           */
    56     67           memset(&sParse, 0, sizeof(sParse));
    57         -        sParse.db = db;
           68  +        sParse.db = pData->db;
    58     69           sParse.initFlag = 1;
    59     70           sParse.isTemp = argv[4][0] - '0';
    60     71           sParse.newTnum = atoi(argv[2]);
    61         -        sqliteRunParser(&sParse, argv[3], 0);
           72  +        sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
    62     73         }else{
    63     74           /* If the SQL column is blank it means this is an index that
    64     75           ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
    65     76           ** constraint for a CREATE TABLE.  The index should have already
    66     77           ** been created when we processed the CREATE TABLE.  All we have
    67     78           ** to do here is record the root page number for that index.
    68     79           */
    69         -        Index *pIndex = sqliteFindIndex(db, argv[1]);
           80  +        Index *pIndex = sqliteFindIndex(pData->db, argv[1]);
    70     81           if( pIndex==0 || pIndex->tnum!=0 ){
    71     82             /* This can occur if there exists an index on a TEMP table which
    72     83             ** has the same name as another index on a permanent index.  Since
    73     84             ** the permanent table is hidden by the TEMP table, we can also
    74     85             ** safely ignore the index on the permanent table.
    75     86             */
    76     87             /* Do Nothing */;
................................................................................
    94    105   ** name of the table to be reconstructed is passed in as argv[0].
    95    106   **
    96    107   ** This routine is used to automatically upgrade a database from
    97    108   ** format version 1 or 2 to version 3.  The correct operation of
    98    109   ** this routine relys on the fact that no indices are used when
    99    110   ** copying a table out to a temporary file.
   100    111   */
   101         -static int 
   102         -upgrade_3_callback(void *pDb, int argc, char **argv, char **NotUsed){
   103         -  sqlite *db = (sqlite*)pDb;
          112  +static
          113  +int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
          114  +  InitData *pData = (InitData*)pInit;
   104    115     int rc;
   105    116     Table *pTab;
   106    117     Trigger *pTrig;
          118  +  char *zErr;
   107    119   
   108         -  pTab = sqliteFindTable(db, argv[0]);
          120  +  pTab = sqliteFindTable(pData->db, argv[0]);
   109    121     if( pTab ){
   110    122       pTrig = pTab->pTrigger;
   111    123       pTab->pTrigger = 0;  /* Disable all triggers before rebuilding the table */
   112    124     }
   113         -  rc = sqlite_exec_printf(db,
          125  +  rc = sqlite_exec_printf(pData->db,
   114    126       "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; "
   115    127       "DELETE FROM '%q'; "
   116    128       "INSERT INTO '%q' SELECT * FROM sqlite_x; "
   117    129       "DROP TABLE sqlite_x;",
   118         -    0, 0, 0, argv[0], argv[0], argv[0]);
          130  +    0, 0, &zErr, argv[0], argv[0], argv[0]);
          131  +  if( zErr ){
          132  +    sqliteSetString(pData->pzErrMsg, zErr, 0);
          133  +    sqlite_freemem(zErr);
          134  +  }
   119    135     if( pTab ) pTab->pTrigger = pTrig;  /* Re-enable triggers */
   120    136     return rc!=SQLITE_OK;
   121    137   }
   122    138   
   123    139   
   124    140   
   125    141   /*
................................................................................
   138    154     int rc;
   139    155     BtCursor *curMain;
   140    156     int size;
   141    157     Table *pTab;
   142    158     char *azArg[6];
   143    159     int meta[SQLITE_N_BTREE_META];
   144    160     Parse sParse;
          161  +  InitData initData;
   145    162   
   146    163     /*
   147    164     ** The master database table has a structure like this
   148    165     */
   149    166     static char master_schema[] = 
   150    167        "CREATE TABLE sqlite_master(\n"
   151    168        "  type text,\n"
................................................................................
   197    214     */
   198    215     azArg[0] = "table";
   199    216     azArg[1] = MASTER_NAME;
   200    217     azArg[2] = "2";
   201    218     azArg[3] = master_schema;
   202    219     azArg[4] = "0";
   203    220     azArg[5] = 0;
   204         -  sqliteInitCallback(db, 5, azArg, 0);
          221  +  initData.db = db;
          222  +  initData.pzErrMsg = pzErrMsg;
          223  +  sqliteInitCallback(&initData, 5, azArg, 0);
   205    224     pTab = sqliteFindTable(db, MASTER_NAME);
   206    225     if( pTab ){
   207    226       pTab->readOnly = 1;
   208    227     }
   209    228     azArg[1] = TEMP_MASTER_NAME;
   210    229     azArg[3] = temp_master_schema;
   211    230     azArg[4] = "1";
   212         -  sqliteInitCallback(db, 5, azArg, 0);
          231  +  sqliteInitCallback(&initData, 5, azArg, 0);
   213    232     pTab = sqliteFindTable(db, TEMP_MASTER_NAME);
   214    233     if( pTab ){
   215    234       pTab->readOnly = 1;
   216    235     }
   217    236   
   218    237     /* Create a cursor to hold the database open
   219    238     */
................................................................................
   254    273   
   255    274     /* Read the schema information out of the schema tables
   256    275     */
   257    276     memset(&sParse, 0, sizeof(sParse));
   258    277     sParse.db = db;
   259    278     sParse.pBe = db->pBe;
   260    279     sParse.xCallback = sqliteInitCallback;
   261         -  sParse.pArg = (void*)db;
          280  +  sParse.pArg = (void*)&initData;
   262    281     sParse.initFlag = 1;
   263    282     sqliteRunParser(&sParse,
   264    283         db->file_format>=2 ? init_script : older_init_script,
   265    284         pzErrMsg);
   266    285     if( sqlite_malloc_failed ){
   267    286       sqliteSetString(pzErrMsg, "out of memory", 0);
   268    287       sParse.rc = SQLITE_NOMEM;
................................................................................
   351    370   
   352    371     /* If the database is in formats 1 or 2, then upgrade it to
   353    372     ** version 3.  This will reconstruct all indices.  If the
   354    373     ** upgrade fails for any reason (ex: out of disk space, database
   355    374     ** is read only, interrupt receive, etc.) then refuse to open.
   356    375     */
   357    376     if( db->file_format<3 ){
   358         -    char *zErr;
          377  +    char *zErr = 0;
          378  +    InitData initData;
   359    379       int meta[SQLITE_N_BTREE_META];
   360    380   
          381  +    initData.db = db;
          382  +    initData.pzErrMsg = &zErr;
   361    383       db->file_format = 3;
   362    384       rc = sqlite_exec(db,
   363    385         "BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
   364    386         upgrade_3_callback,
   365         -      db,
          387  +      &initData,
   366    388         &zErr);
   367    389       if( rc==SQLITE_OK ){
   368    390         sqliteBtreeGetMeta(db->pBe, meta);
   369    391         meta[2] = 3;
   370    392         sqliteBtreeUpdateMeta(db->pBe, meta);
   371    393         sqlite_exec(db, "COMMIT", 0, 0, 0);
   372    394       }
   373    395       if( rc!=SQLITE_OK ){
   374    396         sqliteSetString(pzErrMsg, 
   375    397           "unable to upgrade database to the version 2.6 format",
   376    398           zErr ? ": " : 0, zErr, 0);
   377         -      sqliteFree(zErr);
          399  +      sqlite_freemem(zErr);
   378    400         sqliteStrRealloc(pzErrMsg);
   379    401         sqlite_close(db);
   380    402         return 0;
   381    403       }
          404  +    sqlite_freemem(zErr);
   382    405     }
   383    406   
   384    407     /* Return a pointer to the newly opened database structure */
   385    408     return db;
   386    409   
   387    410   no_mem_on_open:
   388    411     sqliteSetString(pzErrMsg, "out of memory", 0);

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.139 2002/07/18 00:34:12 drh Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.140 2002/07/19 17:46:39 drh Exp $
    15     15   */
    16     16   #include "sqlite.h"
    17     17   #include "hash.h"
    18     18   #include "vdbe.h"
    19     19   #include "parse.h"
    20     20   #include "btree.h"
    21     21   #include <stdio.h>
................................................................................
   945    945   void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
   946    946   TriggerStep *sqliteTriggerSelectStep(Select*);
   947    947   TriggerStep *sqliteTriggerInsertStep(Token*, IdList*, ExprList*, Select*, int);
   948    948   TriggerStep *sqliteTriggerUpdateStep(Token*, ExprList*, Expr*, int);
   949    949   TriggerStep *sqliteTriggerDeleteStep(Token*, Expr*);
   950    950   void sqliteDeleteTrigger(Trigger*);
   951    951   int sqliteJoinType(Parse*, Token*, Token*, Token*);
   952         -int sqliteInitCallback(void*,int,char**,char**);

Changes to test/version.test.

     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing the ability of the library to detect
    13     13   # past or future file format version numbers and respond appropriately.
    14     14   #
    15         -# $Id: version.test,v 1.2 2002/07/18 02:07:08 drh Exp $
           15  +# $Id: version.test,v 1.3 2002/07/19 17:46:41 drh Exp $
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   # Current file format version
    21     21   set VX 3
    22     22   
................................................................................
   173    173     eval btree_update_meta $::bt $m2
   174    174     btree_commit $::bt
   175    175     btree_close $::bt
   176    176     catch {file attributes test.db -permissions 0444}
   177    177     catch {file attributes test.db -readonly 1}
   178    178     set rc [catch {sqlite db test.db} msg]
   179    179     lappend rc $msg
   180         -} {1 {unable to upgrade database to the version 2.6 format}}
          180  +} {1 {unable to upgrade database to the version 2.6 format: attempt to write a readonly database}}
   181    181   
   182    182   finish_test