/ Check-in [1f43219a]
Login

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

Overview
Comment:Fix for #764. When reloading the schema, load the temp schema last. (CVS 1628)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:1f43219a7402af7255743466731dba2afb31d12b
User & Date: danielk1977 2004-06-19 02:22:10
Context
2004-06-19
03:26
Update sqlite.def for version 3.0. (CVS 1629) check-in: 327780ad user: drh tags: trunk
02:22
Fix for #764. When reloading the schema, load the temp schema last. (CVS 1628) check-in: 1f43219a user: danielk1977 tags: trunk
02:19
fix dependencies for testfixture in Makefile.in (CVS 1627) check-in: 26676538 user: dougcurrie tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

    19     19   **     DROP INDEX
    20     20   **     creating ID lists
    21     21   **     BEGIN TRANSACTION
    22     22   **     COMMIT
    23     23   **     ROLLBACK
    24     24   **     PRAGMA
    25     25   **
    26         -** $Id: build.c,v 1.222 2004/06/18 06:02:35 danielk1977 Exp $
           26  +** $Id: build.c,v 1.223 2004/06/19 02:22:10 danielk1977 Exp $
    27     27   */
    28     28   #include "sqliteInt.h"
    29     29   #include <ctype.h>
    30     30   
    31     31   /*
    32     32   ** This routine is called when a new SQL statement is beginning to
    33     33   ** be parsed.  Check to see if the schema for the database needs
................................................................................
   652    652     ** PRIMARY KEY or UNIQUE keywords are parsed.  Those keywords will cause
   653    653     ** indices to be created and the table record must come before the 
   654    654     ** indices.  Hence, the record number for the table must be allocated
   655    655     ** now.
   656    656     */
   657    657     if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
   658    658       sqlite3BeginWriteOperation(pParse, 0, iDb);
   659         -    if( !isTemp ){
   660         -      /* Every time a new table is created the file-format
   661         -      ** and encoding meta-values are set in the database, in
   662         -      ** case this is the first table created.
   663         -      */
   664         -      sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
   665         -      sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
   666         -      sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
   667         -      sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
   668         -    }
          659  +    /* Every time a new table is created the file-format
          660  +    ** and encoding meta-values are set in the database, in
          661  +    ** case this is the first table created.
          662  +    */
          663  +    sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
          664  +    sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
          665  +    sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
          666  +    sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
          667  +
   669    668       sqlite3OpenMasterTable(v, iDb);
   670    669       sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
   671    670       sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
   672    671       sqlite3VdbeAddOp(v, OP_String8, 0, 0);
   673    672       sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
   674    673     }
   675    674   }

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.226 2004/06/18 17:10:17 drh Exp $
           17  +** $Id: main.c,v 1.227 2004/06/19 02:22:11 danielk1977 Exp $
    18     18   */
    19     19   #include "sqliteInt.h"
    20     20   #include "os.h"
    21     21   #include <ctype.h>
    22     22   
    23     23   /*
    24     24   ** A pointer to this structure is used to communicate information
................................................................................
   138    138   ** indicate success or failure.
   139    139   */
   140    140   static int sqlite3InitOne(sqlite *db, int iDb, char **pzErrMsg){
   141    141     int rc;
   142    142     BtCursor *curMain;
   143    143     int size;
   144    144     Table *pTab;
   145         -  char *azArg[6];
          145  +  char const *azArg[6];
   146    146     char zDbNum[30];
   147    147     int meta[10];
   148    148     InitData initData;
          149  +  char const *zMasterSchema;
          150  +  char const *zMasterName;
   149    151   
   150    152     /*
   151    153     ** The master database table has a structure like this
   152    154     */
   153    155     static char master_schema[] = 
   154    156        "CREATE TABLE sqlite_master(\n"
   155    157        "  type text,\n"
................................................................................
   165    167        "  name text,\n"
   166    168        "  tbl_name text,\n"
   167    169        "  rootpage integer,\n"
   168    170        "  sql text\n"
   169    171        ")"
   170    172     ;
   171    173   
   172         -  /* The following SQL will read the schema from the master tables.
          174  +  assert( iDb>=0 && iDb<db->nDb );
          175  +
          176  +  /* zMasterSchema and zInitScript are set to point at the master schema
          177  +  ** and initialisation script appropriate for the database being
          178  +  ** initialised. zMasterName is the name of the master table.
   173    179     */
   174         -  static char init_script1[] = 
   175         -     "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master";
   176         -  static char init_script2[] = 
   177         -     "SELECT type, name, rootpage, sql, 0 FROM sqlite_master";
          180  +  if( iDb==1 ){
          181  +    zMasterSchema = temp_master_schema;
          182  +    zMasterName = TEMP_MASTER_NAME;
          183  +  }else{
          184  +    zMasterSchema = master_schema;
          185  +    zMasterName = MASTER_NAME;
          186  +  }
   178    187   
   179         -  assert( iDb>=0 && iDb!=1 && iDb<db->nDb );
   180         -
   181         -  /* Construct the schema tables: sqlite_master and sqlite_temp_master
   182         -  */
          188  +  /* Construct the schema tables.  */
   183    189     sqlite3SafetyOff(db);
   184    190     azArg[0] = "table";
   185         -  azArg[1] = MASTER_NAME;
          191  +  azArg[1] = zMasterName;
   186    192     azArg[2] = "1";
   187         -  azArg[3] = master_schema;
          193  +  azArg[3] = zMasterSchema;
   188    194     sprintf(zDbNum, "%d", iDb);
   189    195     azArg[4] = zDbNum;
   190    196     azArg[5] = 0;
   191    197     initData.db = db;
   192    198     initData.pzErrMsg = pzErrMsg;
   193         -  sqlite3InitCallback(&initData, 5, azArg, 0);
   194         -  pTab = sqlite3FindTable(db, MASTER_NAME, "main");
          199  +  sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
          200  +  pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
   195    201     if( pTab ){
   196    202       pTab->readOnly = 1;
   197    203     }
   198         -  if( iDb==0 ){
   199         -    azArg[1] = TEMP_MASTER_NAME;
   200         -    azArg[3] = temp_master_schema;
   201         -    azArg[4] = "1";
   202         -    sqlite3InitCallback(&initData, 5, azArg, 0);
   203         -    pTab = sqlite3FindTable(db, TEMP_MASTER_NAME, "temp");
   204         -    if( pTab ){
   205         -      pTab->readOnly = 1;
   206         -    }
   207         -  }
   208    204     sqlite3SafetyOn(db);
   209    205   
   210    206     /* Create a cursor to hold the database open
   211    207     */
   212    208     if( db->aDb[iDb].pBt==0 ) return SQLITE_OK;
   213    209     rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain);
   214    210     if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
................................................................................
   303    299     /* Read the schema information out of the schema tables
   304    300     */
   305    301     assert( db->init.busy );
   306    302     if( rc==SQLITE_EMPTY ){
   307    303       /* For an empty database, there is nothing to read */
   308    304       rc = SQLITE_OK;
   309    305     }else{
          306  +    char *zSql = 0;
   310    307       sqlite3SafetyOff(db);
   311         -    if( iDb==0 ){
   312         -      /* This SQL statement tries to read the temp.* schema from the
   313         -      ** sqlite_temp_master table. It might return SQLITE_EMPTY. 
   314         -      */
   315         -      rc = sqlite3_exec(db, init_script1, sqlite3InitCallback, &initData, 0);
   316         -      if( rc==SQLITE_OK || rc==SQLITE_EMPTY ){
   317         -        rc = sqlite3_exec(db, init_script2, sqlite3InitCallback, &initData, 0);
   318         -      }
   319         -    }else{
   320         -      char *zSql = 0;
   321         -      sqlite3SetString(&zSql, 
   322         -         "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
   323         -         db->aDb[iDb].zName, "\".sqlite_master", (char*)0);
   324         -      rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
   325         -      sqliteFree(zSql);
   326         -    }
          308  +    sqlite3SetString(&zSql, 
          309  +        "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
          310  +        db->aDb[iDb].zName, "\".", zMasterName, (char*)0);
          311  +    rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
          312  +    sqliteFree(zSql);
   327    313       sqlite3SafetyOn(db);
   328    314       sqlite3BtreeCloseCursor(curMain);
   329    315     }
   330    316     if( sqlite3_malloc_failed ){
   331    317       sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
   332    318       rc = SQLITE_NOMEM;
   333    319       sqlite3ResetInternalSchema(db, 0);
   334    320     }
   335    321     if( rc==SQLITE_OK ){
   336    322       DbSetProperty(db, iDb, DB_SchemaLoaded);
   337         -    if( iDb==0 ){
   338         -      DbSetProperty(db, 1, DB_SchemaLoaded);
   339         -    }
   340    323     }else{
   341    324       sqlite3ResetInternalSchema(db, iDb);
   342    325     }
   343    326     return rc;
   344    327   }
   345    328   
   346    329   /*
................................................................................
   356    339     int i, rc;
   357    340     
   358    341     if( db->init.busy ) return SQLITE_OK;
   359    342     assert( (db->flags & SQLITE_Initialized)==0 );
   360    343     rc = SQLITE_OK;
   361    344     db->init.busy = 1;
   362    345     for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
   363         -    if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
   364         -    assert( i!=1 );  /* Should have been initialized together with 0 */
          346  +    if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
   365    347       rc = sqlite3InitOne(db, i, pzErrMsg);
   366    348       if( rc ){
   367    349         sqlite3ResetInternalSchema(db, i);
   368    350       }
   369    351     }
          352  +
          353  +  /* Once all the other databases have been initialised, load the schema
          354  +  ** for the TEMP database. This is loaded last, as the TEMP database
          355  +  ** schema may contain references to objects in other databases.
          356  +  */
          357  +  if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
          358  +    rc = sqlite3InitOne(db, 1, pzErrMsg);
          359  +    if( rc ){
          360  +      sqlite3ResetInternalSchema(db, 1);
          361  +    }
          362  +  }
          363  +
   370    364     db->init.busy = 0;
   371    365     if( rc==SQLITE_OK ){
   372    366       db->flags |= SQLITE_Initialized;
   373    367       sqlite3CommitInternalChanges(db);
   374    368     }
   375    369   
   376    370     if( rc!=SQLITE_OK ){

Changes to test/attach3.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 script is testing the ATTACH and DETACH commands
    13     13   # and schema changes to attached databases.
    14     14   #
    15         -# $Id: attach3.test,v 1.7 2004/06/19 00:16:31 drh Exp $
           15  +# $Id: attach3.test,v 1.8 2004/06/19 02:22:11 danielk1977 Exp $
    16     16   #
    17     17   
    18     18   
    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   # Create tables t1 and t2 in the main database
................................................................................
   207    207   } {1}
   208    208   do_test attach3-9.2 {
   209    209     execsql {
   210    210       DROP TABLE aux.t4;
   211    211       SELECT count(*) FROM sqlite_temp_master;
   212    212     }
   213    213   } {0}
          214  +
          215  +# Make sure the aux.sqlite_master table is read-only
          216  +do_test attach3-10.0 {
          217  +  catchsql {
          218  +    INSERT INTO aux.sqlite_master VALUES(1, 2, 3, 4, 5);
          219  +  }
          220  +} {1 {table sqlite_master may not be modified}}
          221  +
   214    222   
   215    223   finish_test
   216    224   
   217    225   
   218    226   
   219    227   

Changes to test/trigger1.test.

   408    408   do_test trigger-9.2 {
   409    409     execsql {
   410    410       INSERT INTO t3 VALUES(1,3);
   411    411       SELECT * FROM t3 UNION ALL SELECT 99, 99 UNION ALL SELECT * FROM t4;
   412    412     }
   413    413   } {1 2 1 3 99 99 1 3}
   414    414   
          415  +execsql {
          416  +  DROP TABLE t2;
          417  +  DROP TABLE t3;
          418  +  DROP TABLE t4;
          419  +}
          420  +
          421  +# Ticket #764. At one stage TEMP triggers would fail to re-install when the
          422  +# schema was reloaded. The following tests ensure that TEMP triggers are
          423  +# correctly re-installed.
          424  +#
          425  +# Also verify that references within trigger programs are resolved at
          426  +# statement compile time, not trigger installation time. This means, for
          427  +# example, that you can drop and re-create tables referenced by triggers. 
          428  +do_test trigger-10.0 {
          429  +  file delete -force test2.db
          430  +  file delete -force test2.db-journal
          431  +  execsql {
          432  +    ATTACH 'test2.db' AS aux;
          433  +  }
          434  +} {}
          435  +do_test trigger-10.1 {
          436  +  execsql {
          437  +    CREATE TABLE main.t4(a, b, c);
          438  +    CREATE TABLE temp.t4(a, b, c);
          439  +    CREATE TABLE aux.t4(a, b, c);
          440  +    CREATE TABLE insert_log(db, a, b, c);
          441  +  }
          442  +} {}
          443  +do_test trigger-10.2 {
          444  +  execsql {
          445  +    CREATE TEMP TRIGGER trig1 AFTER INSERT ON main.t4 BEGIN 
          446  +      INSERT INTO insert_log VALUES('main', new.a, new.b, new.c);
          447  +    END;
          448  +    CREATE TEMP TRIGGER trig2 AFTER INSERT ON temp.t4 BEGIN 
          449  +      INSERT INTO insert_log VALUES('temp', new.a, new.b, new.c);
          450  +    END;
          451  +    CREATE TEMP TRIGGER trig3 AFTER INSERT ON aux.t4 BEGIN 
          452  +      INSERT INTO insert_log VALUES('aux', new.a, new.b, new.c);
          453  +    END;
          454  +  }
          455  +} {}
          456  +do_test trigger-10.3 {
          457  +  execsql {
          458  +    INSERT INTO main.t4 VALUES(1, 2, 3);
          459  +    INSERT INTO temp.t4 VALUES(4, 5, 6);
          460  +    INSERT INTO aux.t4  VALUES(7, 8, 9);
          461  +  }
          462  +} {}
          463  +do_test trigger-10.4 {
          464  +  execsql {
          465  +    SELECT * FROM insert_log;
          466  +  }
          467  +} {main 1 2 3 temp 4 5 6 aux 7 8 9}
          468  +do_test trigger-10.5 {
          469  +  execsql {
          470  +    BEGIN;
          471  +    INSERT INTO main.t4 VALUES(1, 2, 3);
          472  +    INSERT INTO temp.t4 VALUES(4, 5, 6);
          473  +    INSERT INTO aux.t4  VALUES(7, 8, 9);
          474  +    ROLLBACK;
          475  +  }
          476  +} {}
          477  +do_test trigger-10.6 {
          478  +  execsql {
          479  +    SELECT * FROM insert_log;
          480  +  }
          481  +} {main 1 2 3 temp 4 5 6 aux 7 8 9}
          482  +do_test trigger-10.7 {
          483  +  execsql {
          484  +    DELETE FROM insert_log;
          485  +    INSERT INTO main.t4 VALUES(11, 12, 13);
          486  +    INSERT INTO temp.t4 VALUES(14, 15, 16);
          487  +    INSERT INTO aux.t4  VALUES(17, 18, 19);
          488  +  }
          489  +} {}
          490  +do_test trigger-10.8 {
          491  +  execsql {
          492  +    SELECT * FROM insert_log;
          493  +  }
          494  +} {main 11 12 13 temp 14 15 16 aux 17 18 19}
          495  +do_test trigger-10.8 {
          496  +# Drop and re-create the insert_log table in a different database. Note
          497  +# that we can change the column names because the trigger programs don't
          498  +# use them explicitly.
          499  +  execsql {
          500  +    DROP TABLE insert_log;
          501  +    CREATE TABLE aux.insert_log(db, d, e, f);
          502  +  }
          503  +} {}
          504  +do_test trigger-10.10 {
          505  +  execsql {
          506  +    INSERT INTO main.t4 VALUES(21, 22, 23);
          507  +    INSERT INTO temp.t4 VALUES(24, 25, 26);
          508  +    INSERT INTO aux.t4  VALUES(27, 28, 29);
          509  +  }
          510  +} {}
          511  +do_test trigger-10.11 {
          512  +  execsql {
          513  +    SELECT * FROM insert_log;
          514  +  }
          515  +} {main 21 22 23 temp 24 25 26 aux 27 28 29}
   415    516   
   416    517   finish_test