SQLite

Check-in [1b736ac293]
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
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 1b736ac2934f2361dee5062e9033cbf26b41fc3a
User & Date: drh 2011-03-19 02:37:38.712
Context
2011-03-19
08:38
Fix a problem with INTEGER PRIMARY KEY columns and the pre-update hook. (check-in: 24d4d5dd00 user: dan tags: sessions)
02:37
Merge the fix to ticket [f7b4edece25c99485] into the sessions branch. (check-in: 1b736ac293 user: drh tags: sessions)
02:04
Add a test case to verify that ticket [f7b4edece25c994857] is fixed. (check-in: eedbcf0a0b 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: c615c38c32 user: dan tags: sessions)
Changes
Unified Diff Ignore Whitespace Patch
install-sh became executable.
Changes to src/build.c.
152
153
154
155
156
157
158

159

160
161
162
163
164
165
166
      int iDb;
      sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
      for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
        if( (mask & pParse->cookieMask)==0 ) continue;
        sqlite3VdbeUsesBtree(v, iDb);
        sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
        if( db->init.busy==0 ){

          sqlite3VdbeAddOp2(v,OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);

        }
      }
#ifndef SQLITE_OMIT_VIRTUALTABLE
      {
        int i;
        for(i=0; i<pParse->nVtabLock; i++){
          char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);







>
|
>







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


430

431
432
433
434
435
436
437
  for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTab = sqliteHashData(pElem);
    sqlite3DeleteTable(0, pTab);
  }
  sqlite3HashClear(&temp1);
  sqlite3HashClear(&pSchema->fkeyHash);
  pSchema->pSeqTab = 0;


  pSchema->flags &= ~DB_SchemaLoaded;

}

/*
** Find and return the schema associated with a BTree.  Create
** a new one if necessary.
*/
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){







>
>
|
>







423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTab = sqliteHashData(pElem);
    sqlite3DeleteTable(0, pTab);
  }
  sqlite3HashClear(&temp1);
  sqlite3HashClear(&pSchema->fkeyHash);
  pSchema->pSeqTab = 0;
  if( pSchema->flags & DB_SchemaLoaded ){
    pSchema->iGeneration++;
    pSchema->flags &= ~DB_SchemaLoaded;
  }
}

/*
** Find and return the schema associated with a BTree.  Create
** a new one if necessary.
*/
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
Changes to src/sqliteInt.h.
668
669
670
671
672
673
674

675
676
677
678
679
680
681
};

/*
** An instance of the following structure stores a database schema.
*/
struct Schema {
  int schema_cookie;   /* Database schema version number for this file */

  Hash tblHash;        /* All tables indexed by name */
  Hash idxHash;        /* All (named) indices indexed by name */
  Hash trigHash;       /* All triggers indexed by name */
  Hash fkeyHash;       /* All foreign keys by referenced table name */
  Table *pSeqTab;      /* The sqlite_sequence table used by AUTOINCREMENT */
  u8 file_format;      /* Schema format version for this file */
  u8 enc;              /* Text encoding used by this database */







>







668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
};

/*
** An instance of the following structure stores a database schema.
*/
struct Schema {
  int schema_cookie;   /* Database schema version number for this file */
  int iGeneration;     /* Generation counter.  Incremented with each change */
  Hash tblHash;        /* All tables indexed by name */
  Hash idxHash;        /* All (named) indices indexed by name */
  Hash trigHash;       /* All triggers indexed by name */
  Hash fkeyHash;       /* All foreign keys by referenced table name */
  Table *pSeqTab;      /* The sqlite_sequence table used by AUTOINCREMENT */
  u8 file_format;      /* Schema format version for this file */
  u8 enc;              /* Text encoding used by this database */
Changes to src/vdbe.c.
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896


2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910

2911

2912
2913
2914
2915
2916

2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
    ** schema is changed.  Ticket #1644 */
    sqlite3ExpirePreparedStatements(db);
    p->expired = 0;
  }
  break;
}

/* Opcode: VerifyCookie P1 P2 *
**
** Check the value of global database parameter number 0 (the
** schema version) and make sure it is equal to P2.  


** P1 is the database number which is 0 for the main database file
** and 1 for the file holding temporary tables and some higher number
** for auxiliary databases.
**
** The cookie changes its value whenever the database schema changes.
** This operation is used to detect when that the cookie has changed
** and that the current process needs to reread the schema.
**
** Either a transaction needs to have been started or an OP_Open needs
** to be executed (to establish a read lock) before this opcode is
** invoked.
*/
case OP_VerifyCookie: {
  int iMeta;

  Btree *pBt;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  assert( (p->btreeMask & (1<<pOp->p1))!=0 );
  pBt = db->aDb[pOp->p1].pBt;
  if( pBt ){
    sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);

  }else{
    iMeta = 0;
  }
  if( iMeta!=pOp->p2 ){
    sqlite3DbFree(db, p->zErrMsg);
    p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
    /* If the schema-cookie from the database file matches the cookie 
    ** stored with the in-memory representation of the schema, do
    ** not reload the schema from the database file.
    **
    ** If virtual-tables are in use, this is not just an optimization.







|


|
>
>














>

>





>



|







2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
    ** schema is changed.  Ticket #1644 */
    sqlite3ExpirePreparedStatements(db);
    p->expired = 0;
  }
  break;
}

/* Opcode: VerifyCookie P1 P2 P3 * *
**
** Check the value of global database parameter number 0 (the
** schema version) and make sure it is equal to P2 and that the
** generation counter on the local schema parse equals P3.
**
** P1 is the database number which is 0 for the main database file
** and 1 for the file holding temporary tables and some higher number
** for auxiliary databases.
**
** The cookie changes its value whenever the database schema changes.
** This operation is used to detect when that the cookie has changed
** and that the current process needs to reread the schema.
**
** Either a transaction needs to have been started or an OP_Open needs
** to be executed (to establish a read lock) before this opcode is
** invoked.
*/
case OP_VerifyCookie: {
  int iMeta;
  int iGen;
  Btree *pBt;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  assert( (p->btreeMask & (1<<pOp->p1))!=0 );
  pBt = db->aDb[pOp->p1].pBt;
  if( pBt ){
    sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
    iGen = db->aDb[pOp->p1].pSchema->iGeneration;
  }else{
    iMeta = 0;
  }
  if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){
    sqlite3DbFree(db, p->zErrMsg);
    p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
    /* If the schema-cookie from the database file matches the cookie 
    ** stored with the in-memory representation of the schema, do
    ** not reload the schema from the database file.
    **
    ** If virtual-tables are in use, this is not just an optimization.
Changes to src/vdbeblob.c.
262
263
264
265
266
267
268

269
270
271
272
273
274
275
      /* Configure the OP_Transaction */
      sqlite3VdbeChangeP1(v, 0, iDb);
      sqlite3VdbeChangeP2(v, 0, flags);

      /* Configure the OP_VerifyCookie */
      sqlite3VdbeChangeP1(v, 1, iDb);
      sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);


      /* Make sure a mutex is held on the table to be accessed */
      sqlite3VdbeUsesBtree(v, iDb); 

      /* Configure the OP_TableLock instruction */
#ifdef SQLITE_OMIT_SHARED_CACHE
      sqlite3VdbeChangeToNoop(v, 2, 1);







>







262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
      /* Configure the OP_Transaction */
      sqlite3VdbeChangeP1(v, 0, iDb);
      sqlite3VdbeChangeP2(v, 0, flags);

      /* Configure the OP_VerifyCookie */
      sqlite3VdbeChangeP1(v, 1, iDb);
      sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
      sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);

      /* Make sure a mutex is held on the table to be accessed */
      sqlite3VdbeUsesBtree(v, iDb); 

      /* Configure the OP_TableLock instruction */
#ifdef SQLITE_OMIT_SHARED_CACHE
      sqlite3VdbeChangeToNoop(v, 2, 1);
Changes to test/capi3.test.
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
} {0}
do_test capi3-6.1 {
  db cache flush
  sqlite3_close $DB
} {SQLITE_BUSY}
do_test capi3-6.2 {
  sqlite3_step $STMT
} {SQLITE_ROW}
check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
do_test capi3-6.3 {
  sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3-6.4-misuse {
  db cache flush
  sqlite3_close $DB
} {SQLITE_OK}
db close

# This procedure sets the value of the file-format in file 'test.db'







|
|


|







647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
} {0}
do_test capi3-6.1 {
  db cache flush
  sqlite3_close $DB
} {SQLITE_BUSY}
do_test capi3-6.2 {
  sqlite3_step $STMT
} {SQLITE_ERROR}
#check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
do_test capi3-6.3 {
  sqlite3_finalize $STMT
} {SQLITE_SCHEMA}
do_test capi3-6.4-misuse {
  db cache flush
  sqlite3_close $DB
} {SQLITE_OK}
db close

# 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
2
3
4
5
6
7
8
9
10
11
12
13
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
# 2011 March 18
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to verify that ticket 
# [f7b4edece25c994857dc139207f55a53c8319fae] has been fixed.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Open two database connections to the same database file in
# shared cache mode.  Create update hooks that will fire on
# each connection.
#
db close
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
sqlite3 db1 test.db
sqlite3 db2 test.db
unset -nocomplain HOOKS
set HOOKS {}
proc update_hook {args} { lappend ::HOOKS $args }
db1 update_hook update_hook
db2 update_hook update_hook

# Create a prepared statement
#
do_test tkt-f7b4edec-1 {
  execsql { CREATE TABLE t1(x, y); } db1
  execsql { INSERT INTO t1 VALUES(1, 2) } db1
  set ::HOOKS
} {{INSERT main t1 1}}

# In the second database connection cause the schema to be reparsed
# without changing the schema cookie.
#
set HOOKS {}
do_test tkt-f7b4edec-2 {
  execsql {
    BEGIN;
      DROP TABLE t1;
      CREATE TABLE t1(x, y);
    ROLLBACK;
  } db2
  set ::HOOKS
} {}

# Rerun the prepared statement that was created prior to the 
# schema reparse.  Verify that the update-hook gives the correct
# output.
#
set HOOKS {}
do_test tkt-f7b4edec-3 {
  execsql { INSERT INTO t1 VALUES(1, 2) } db1
  set ::HOOKS
} {{INSERT main t1 2}}

# Be sure to restore the original shared-cache mode setting before
# returning.
#
db1 close
db2 close
sqlite3_enable_shared_cache $::enable_shared_cache


finish_test
tool/mkopts.tcl became a regular file.