/ Check-in [1b736ac2]
Login

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

Overview
Comment:Merge the fix to ticket [f7b4edece25c99485] into the sessions branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 1b736ac2934f2361dee5062e9033cbf26b41fc3a
User & Date: drh 2011-03-19 02:37:38
Context
2011-03-19
08:38
Fix a problem with INTEGER PRIMARY KEY columns and the pre-update hook. check-in: 24d4d5dd user: dan tags: sessions
02:37
Merge the fix to ticket [f7b4edece25c99485] into the sessions branch. check-in: 1b736ac2 user: drh tags: sessions
02:04
Add a test case to verify that ticket [f7b4edece25c994857] is fixed. check-in: eedbcf0a user: drh tags: trunk
2011-03-18
18:03
Hold the database mutex for the duration of an sqlite3changeset_apply() call. Also for the duration of all sqlite3session_xxx() calls. check-in: c615c38c user: dan tags: sessions
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

install-sh became executable.


Changes to src/build.c.

   152    152         int iDb;
   153    153         sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
   154    154         for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
   155    155           if( (mask & pParse->cookieMask)==0 ) continue;
   156    156           sqlite3VdbeUsesBtree(v, iDb);
   157    157           sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
   158    158           if( db->init.busy==0 ){
   159         -          sqlite3VdbeAddOp2(v,OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
          159  +          sqlite3VdbeAddOp3(v, OP_VerifyCookie,
          160  +                            iDb, pParse->cookieValue[iDb],
          161  +                            db->aDb[iDb].pSchema->iGeneration);
   160    162           }
   161    163         }
   162    164   #ifndef SQLITE_OMIT_VIRTUALTABLE
   163    165         {
   164    166           int i;
   165    167           for(i=0; i<pParse->nVtabLock; i++){
   166    168             char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);

Changes to src/callback.c.

   423    423     for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
   424    424       Table *pTab = sqliteHashData(pElem);
   425    425       sqlite3DeleteTable(0, pTab);
   426    426     }
   427    427     sqlite3HashClear(&temp1);
   428    428     sqlite3HashClear(&pSchema->fkeyHash);
   429    429     pSchema->pSeqTab = 0;
   430         -  pSchema->flags &= ~DB_SchemaLoaded;
          430  +  if( pSchema->flags & DB_SchemaLoaded ){
          431  +    pSchema->iGeneration++;
          432  +    pSchema->flags &= ~DB_SchemaLoaded;
          433  +  }
   431    434   }
   432    435   
   433    436   /*
   434    437   ** Find and return the schema associated with a BTree.  Create
   435    438   ** a new one if necessary.
   436    439   */
   437    440   Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){

Changes to src/sqliteInt.h.

   668    668   };
   669    669   
   670    670   /*
   671    671   ** An instance of the following structure stores a database schema.
   672    672   */
   673    673   struct Schema {
   674    674     int schema_cookie;   /* Database schema version number for this file */
          675  +  int iGeneration;     /* Generation counter.  Incremented with each change */
   675    676     Hash tblHash;        /* All tables indexed by name */
   676    677     Hash idxHash;        /* All (named) indices indexed by name */
   677    678     Hash trigHash;       /* All triggers indexed by name */
   678    679     Hash fkeyHash;       /* All foreign keys by referenced table name */
   679    680     Table *pSeqTab;      /* The sqlite_sequence table used by AUTOINCREMENT */
   680    681     u8 file_format;      /* Schema format version for this file */
   681    682     u8 enc;              /* Text encoding used by this database */

Changes to src/vdbe.c.

  2886   2886       ** schema is changed.  Ticket #1644 */
  2887   2887       sqlite3ExpirePreparedStatements(db);
  2888   2888       p->expired = 0;
  2889   2889     }
  2890   2890     break;
  2891   2891   }
  2892   2892   
  2893         -/* Opcode: VerifyCookie P1 P2 *
         2893  +/* Opcode: VerifyCookie P1 P2 P3 * *
  2894   2894   **
  2895   2895   ** Check the value of global database parameter number 0 (the
  2896         -** schema version) and make sure it is equal to P2.  
         2896  +** schema version) and make sure it is equal to P2 and that the
         2897  +** generation counter on the local schema parse equals P3.
         2898  +**
  2897   2899   ** P1 is the database number which is 0 for the main database file
  2898   2900   ** and 1 for the file holding temporary tables and some higher number
  2899   2901   ** for auxiliary databases.
  2900   2902   **
  2901   2903   ** The cookie changes its value whenever the database schema changes.
  2902   2904   ** This operation is used to detect when that the cookie has changed
  2903   2905   ** and that the current process needs to reread the schema.
................................................................................
  2904   2906   **
  2905   2907   ** Either a transaction needs to have been started or an OP_Open needs
  2906   2908   ** to be executed (to establish a read lock) before this opcode is
  2907   2909   ** invoked.
  2908   2910   */
  2909   2911   case OP_VerifyCookie: {
  2910   2912     int iMeta;
         2913  +  int iGen;
  2911   2914     Btree *pBt;
         2915  +
  2912   2916     assert( pOp->p1>=0 && pOp->p1<db->nDb );
  2913   2917     assert( (p->btreeMask & (1<<pOp->p1))!=0 );
  2914   2918     pBt = db->aDb[pOp->p1].pBt;
  2915   2919     if( pBt ){
  2916   2920       sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
         2921  +    iGen = db->aDb[pOp->p1].pSchema->iGeneration;
  2917   2922     }else{
  2918   2923       iMeta = 0;
  2919   2924     }
  2920         -  if( iMeta!=pOp->p2 ){
         2925  +  if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){
  2921   2926       sqlite3DbFree(db, p->zErrMsg);
  2922   2927       p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
  2923   2928       /* If the schema-cookie from the database file matches the cookie 
  2924   2929       ** stored with the in-memory representation of the schema, do
  2925   2930       ** not reload the schema from the database file.
  2926   2931       **
  2927   2932       ** If virtual-tables are in use, this is not just an optimization.

Changes to src/vdbeblob.c.

   262    262         /* Configure the OP_Transaction */
   263    263         sqlite3VdbeChangeP1(v, 0, iDb);
   264    264         sqlite3VdbeChangeP2(v, 0, flags);
   265    265   
   266    266         /* Configure the OP_VerifyCookie */
   267    267         sqlite3VdbeChangeP1(v, 1, iDb);
   268    268         sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
          269  +      sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
   269    270   
   270    271         /* Make sure a mutex is held on the table to be accessed */
   271    272         sqlite3VdbeUsesBtree(v, iDb); 
   272    273   
   273    274         /* Configure the OP_TableLock instruction */
   274    275   #ifdef SQLITE_OMIT_SHARED_CACHE
   275    276         sqlite3VdbeChangeToNoop(v, 2, 1);

Changes to test/capi3.test.

   647    647   } {0}
   648    648   do_test capi3-6.1 {
   649    649     db cache flush
   650    650     sqlite3_close $DB
   651    651   } {SQLITE_BUSY}
   652    652   do_test capi3-6.2 {
   653    653     sqlite3_step $STMT
   654         -} {SQLITE_ROW}
   655         -check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
          654  +} {SQLITE_ERROR}
          655  +#check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
   656    656   do_test capi3-6.3 {
   657    657     sqlite3_finalize $STMT
   658         -} {SQLITE_OK}
          658  +} {SQLITE_SCHEMA}
   659    659   do_test capi3-6.4-misuse {
   660    660     db cache flush
   661    661     sqlite3_close $DB
   662    662   } {SQLITE_OK}
   663    663   db close
   664    664   
   665    665   # This procedure sets the value of the file-format in file 'test.db'

test/progress.test became a regular file.


Added test/tkt-f7b4edec.test.

            1  +# 2011 March 18
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.
           12  +#
           13  +# This file implements tests to verify that ticket 
           14  +# [f7b4edece25c994857dc139207f55a53c8319fae] has been fixed.
           15  +#
           16  +
           17  +set testdir [file dirname $argv0]
           18  +source $testdir/tester.tcl
           19  +
           20  +# Open two database connections to the same database file in
           21  +# shared cache mode.  Create update hooks that will fire on
           22  +# each connection.
           23  +#
           24  +db close
           25  +set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
           26  +sqlite3 db1 test.db
           27  +sqlite3 db2 test.db
           28  +unset -nocomplain HOOKS
           29  +set HOOKS {}
           30  +proc update_hook {args} { lappend ::HOOKS $args }
           31  +db1 update_hook update_hook
           32  +db2 update_hook update_hook
           33  +
           34  +# Create a prepared statement
           35  +#
           36  +do_test tkt-f7b4edec-1 {
           37  +  execsql { CREATE TABLE t1(x, y); } db1
           38  +  execsql { INSERT INTO t1 VALUES(1, 2) } db1
           39  +  set ::HOOKS
           40  +} {{INSERT main t1 1}}
           41  +
           42  +# In the second database connection cause the schema to be reparsed
           43  +# without changing the schema cookie.
           44  +#
           45  +set HOOKS {}
           46  +do_test tkt-f7b4edec-2 {
           47  +  execsql {
           48  +    BEGIN;
           49  +      DROP TABLE t1;
           50  +      CREATE TABLE t1(x, y);
           51  +    ROLLBACK;
           52  +  } db2
           53  +  set ::HOOKS
           54  +} {}
           55  +
           56  +# Rerun the prepared statement that was created prior to the 
           57  +# schema reparse.  Verify that the update-hook gives the correct
           58  +# output.
           59  +#
           60  +set HOOKS {}
           61  +do_test tkt-f7b4edec-3 {
           62  +  execsql { INSERT INTO t1 VALUES(1, 2) } db1
           63  +  set ::HOOKS
           64  +} {{INSERT main t1 2}}
           65  +
           66  +# Be sure to restore the original shared-cache mode setting before
           67  +# returning.
           68  +#
           69  +db1 close
           70  +db2 close
           71  +sqlite3_enable_shared_cache $::enable_shared_cache
           72  +
           73  +
           74  +finish_test

tool/mkopts.tcl became a regular file.