SQLite

Check-in [c6c13dc460]
Login

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

Overview
Comment:Store schema cookies on the TEMP database. Ticket #807. (CVS 1817)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c6c13dc460094e6adea2b14849edf9f485238b99
User & Date: drh 2004-07-19 17:25:25.000
Context
2004-07-19
19:14
Fix for ticket #813. (CVS 1818) (check-in: 88e4bfa154 user: drh tags: trunk)
17:25
Store schema cookies on the TEMP database. Ticket #807. (CVS 1817) (check-in: c6c13dc460 user: drh tags: trunk)
04:25
use -lsqlite3 in .pc file (CVS 1816) (check-in: b36e6e4907 user: dougcurrie tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.237 2004/06/29 08:59:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.238 2004/07/19 17:25:25 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

104
105
106
107
108
109
110

    /* The cookie mask contains one bit for each database file open.
    ** (Bit 0 is for main, bit 1 is for temp, and so forth.)  Bits are
    ** set for each database that is used.  Generate code to start a
    ** transaction on each used database and to verify the schema cookie
    ** on each used database.
    */
    if( pParse->cookieMask!=0 ){
      u32 mask;
      int iDb;
      sqlite3VdbeChangeP2(v, pParse->cookieGoto, sqlite3VdbeCurrentAddr(v));
      for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
        if( (mask & pParse->cookieMask)==0 ) continue;
        sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
        if( iDb!=1 ){
          sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
        }
      }
      sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto+1);
    }
  }

  /* Get the VDBE program ready for execution
  */
  if( v && pParse->nErr==0 ){
    FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
    sqlite3VdbeTrace(v, trace);
    sqlite3VdbeMakeReady(v, pParse->nVar, pParse->explain);
    pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
    pParse->colNamesSet = 0;
  }else if( pParse->rc==SQLITE_OK ){
    pParse->rc = SQLITE_ERROR;
  }
  pParse->nTab = 0;
  pParse->nMem = 0;
  pParse->nSet = 0;
  pParse->nAgg = 0;
  pParse->nVar = 0;
  pParse->cookieMask = 0;

}

/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.
**







|


|



<
|
|
<
|




















>







65
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

    /* The cookie mask contains one bit for each database file open.
    ** (Bit 0 is for main, bit 1 is for temp, and so forth.)  Bits are
    ** set for each database that is used.  Generate code to start a
    ** transaction on each used database and to verify the schema cookie
    ** on each used database.
    */
    if( pParse->cookieGoto>0 ){
      u32 mask;
      int iDb;
      sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v));
      for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
        if( (mask & pParse->cookieMask)==0 ) continue;
        sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);

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

      sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
    }
  }

  /* Get the VDBE program ready for execution
  */
  if( v && pParse->nErr==0 ){
    FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
    sqlite3VdbeTrace(v, trace);
    sqlite3VdbeMakeReady(v, pParse->nVar, pParse->explain);
    pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
    pParse->colNamesSet = 0;
  }else if( pParse->rc==SQLITE_OK ){
    pParse->rc = SQLITE_ERROR;
  }
  pParse->nTab = 0;
  pParse->nMem = 0;
  pParse->nSet = 0;
  pParse->nAgg = 0;
  pParse->nVar = 0;
  pParse->cookieMask = 0;
  pParse->cookieGoto = 0;
}

/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.
**
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
      n = Addr(pEnd->z) - Addr(pParse->sNameToken.z) + 1;
      sqlite3VdbeAddOp(v, OP_String8, 0, 0);
      sqlite3VdbeChangeP3(v, -1, pParse->sNameToken.z, n);
      sqlite3VdbeAddOp(v, OP_Concat8, 2, 0);
    }
    sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
    sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
    if( p->iDb!=1 ){
      sqlite3ChangeCookie(db, v, p->iDb);
    }
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);

    sqlite3EndWriteOperation(pParse);
  }

  /* Add the table to the in-memory representation of the database.
  */







<
|
<







1373
1374
1375
1376
1377
1378
1379

1380

1381
1382
1383
1384
1385
1386
1387
      n = Addr(pEnd->z) - Addr(pParse->sNameToken.z) + 1;
      sqlite3VdbeAddOp(v, OP_String8, 0, 0);
      sqlite3VdbeChangeP3(v, -1, pParse->sNameToken.z, n);
      sqlite3VdbeAddOp(v, OP_Concat8, 2, 0);
    }
    sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
    sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);

    sqlite3ChangeCookie(db, v, p->iDb);

    sqlite3VdbeAddOp(v, OP_Close, 0, 0);

    sqlite3EndWriteOperation(pParse);
  }

  /* Add the table to the in-memory representation of the database.
  */
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
                      "indexed columns are not unique", P3_STATIC);
      sqlite3VdbeAddOp(v, OP_Next, 2, lbl1);
      sqlite3VdbeResolveLabel(v, lbl2);
      sqlite3VdbeAddOp(v, OP_Close, 2, 0);
      sqlite3VdbeAddOp(v, OP_Close, 1, 0);
    }
    if( pTblName!=0 ){
      if( !isTemp ){
        sqlite3ChangeCookie(db, v, iDb);
      }
      sqlite3VdbeAddOp(v, OP_Close, 0, 0);
      sqlite3EndWriteOperation(pParse);
    }
  }

  /* When adding an index to the list of indices for a table, make
  ** sure all indices labeled OE_Replace come after all those labeled







<
|
<







2191
2192
2193
2194
2195
2196
2197

2198

2199
2200
2201
2202
2203
2204
2205
                      "indexed columns are not unique", P3_STATIC);
      sqlite3VdbeAddOp(v, OP_Next, 2, lbl1);
      sqlite3VdbeResolveLabel(v, lbl2);
      sqlite3VdbeAddOp(v, OP_Close, 2, 0);
      sqlite3VdbeAddOp(v, OP_Close, 1, 0);
    }
    if( pTblName!=0 ){

      sqlite3ChangeCookie(db, v, iDb);

      sqlite3VdbeAddOp(v, OP_Close, 0, 0);
      sqlite3EndWriteOperation(pParse);
    }
  }

  /* When adding an index to the list of indices for a table, make
  ** sure all indices labeled OE_Replace come after all those labeled
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
    };
    int base;

    sqlite3BeginWriteOperation(pParse, 0, pIndex->iDb);
    sqlite3OpenMasterTable(v, pIndex->iDb);
    base = sqlite3VdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
    sqlite3VdbeChangeP3(v, base+1, pIndex->zName, 0);
    if( pIndex->iDb!=1 ){
      sqlite3ChangeCookie(db, v, pIndex->iDb);
    }
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
    sqlite3EndWriteOperation(pParse);
  }

  /* Delete the in-memory description of this index.
  */







<
|
<







2291
2292
2293
2294
2295
2296
2297

2298

2299
2300
2301
2302
2303
2304
2305
    };
    int base;

    sqlite3BeginWriteOperation(pParse, 0, pIndex->iDb);
    sqlite3OpenMasterTable(v, pIndex->iDb);
    base = sqlite3VdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
    sqlite3VdbeChangeP3(v, base+1, pIndex->zName, 0);

    sqlite3ChangeCookie(db, v, pIndex->iDb);

    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
    sqlite3EndWriteOperation(pParse);
  }

  /* Delete the in-memory description of this index.
  */
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543




2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558




2559
2560
2561
2562

2563
2564
2565
2566
2567
2568
2569
** a read-transaction for all named database files.
**
** It is important that all schema cookies be verified and all
** read transactions be started before anything else happens in
** the VDBE program.  But this routine can be called after much other
** code has been generated.  So here is what we do:
**
** The first time this routine is called, we code an OP_Gosub that
** will jump to a subroutine at the end of the program.  Then we
** record every database that needs its schema verified in the
** pParse->cookieMask field.  Later, after all other code has been
** generated, the subroutine that does the cookie verifications and
** starts the transactions will be coded and the OP_Gosub P2 value
** will be made to point to that subroutine.  The generation of the
** cookie verification subroutine code happens in sqlite3FinishCoding().




*/
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
  sqlite *db;
  Vdbe *v;
  int mask;

  v = sqlite3GetVdbe(pParse);
  if( v==0 ) return;  /* This only happens if there was a prior error */
  db = pParse->db;
  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pBt!=0 || iDb==1 );
  assert( iDb<32 );
  if( pParse->cookieMask==0 ){
    pParse->cookieGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
  }




  mask = 1<<iDb;
  if( (pParse->cookieMask & mask)==0 ){
    pParse->cookieMask |= mask;
    pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie;

  }
}

/*
** Generate VDBE code that prepares for doing an operation that
** might change the database.
**







|




|


>
>
>
>









<
<
<
|
|

>
>
>
>
|
|
|
|
>







2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549



2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
** a read-transaction for all named database files.
**
** It is important that all schema cookies be verified and all
** read transactions be started before anything else happens in
** the VDBE program.  But this routine can be called after much other
** code has been generated.  So here is what we do:
**
** The first time this routine is called, we code an OP_Goto that
** will jump to a subroutine at the end of the program.  Then we
** record every database that needs its schema verified in the
** pParse->cookieMask field.  Later, after all other code has been
** generated, the subroutine that does the cookie verifications and
** starts the transactions will be coded and the OP_Goto P2 value
** will be made to point to that subroutine.  The generation of the
** cookie verification subroutine code happens in sqlite3FinishCoding().
**
** If iDb<0 then code the OP_Goto only - don't set flag to verify the
** schema on any databases.  This can be used to position the OP_Goto
** early in the code, before we know if any database tables will be used.
*/
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
  sqlite *db;
  Vdbe *v;
  int mask;

  v = sqlite3GetVdbe(pParse);
  if( v==0 ) return;  /* This only happens if there was a prior error */
  db = pParse->db;



  if( pParse->cookieGoto==0 ){
    pParse->cookieGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0)+1;
  }
  if( iDb>=0 ){
    assert( iDb<db->nDb );
    assert( db->aDb[iDb].pBt!=0 || iDb==1 );
    assert( iDb<32 );
    mask = 1<<iDb;
    if( (pParse->cookieMask & mask)==0 ){
      pParse->cookieMask |= mask;
      pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie;
    }
  }
}

/*
** Generate VDBE code that prepares for doing an operation that
** might change the database.
**
Changes to src/main.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.244 2004/06/30 11:54:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.245 2004/07/19 17:25:25 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

/*
** This is the callback routine for the code that initializes the
** database.  See sqlite3Init() below for additional information.
**
** Each callback contains the following information:
**
**     argv[0] = "file-format" or "schema-cookie" or "table" or "index"
**     argv[1] = table or index name or meta statement type.
**     argv[2] = root page number for table or index.  NULL for meta.
**     argv[3] = SQL text for a CREATE TABLE or CREATE INDEX statement.
**     argv[4] = "1" for temporary files, "0" for main database, "2" or more
**               for auxiliary database files.
**
*/
static
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
  InitData *pData = (InitData*)pInit;







|
|
|
|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

/*
** This is the callback routine for the code that initializes the
** database.  See sqlite3Init() below for additional information.
**
** Each callback contains the following information:
**
**     argv[0] = "table" or "index" or "view" or "trigger"
**     argv[1] = name of thing being created
**     argv[2] = root page number for table or index.  NULL for trigger or view.
**     argv[3] = SQL text for the CREATE statement.
**     argv[4] = "1" for temporary files, "0" for main database, "2" or more
**               for auxiliary database files.
**
*/
static
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
  InitData *pData = (InitData*)pInit;
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944

int sqlite3_errcode(sqlite3 *db){
  if( !db ) return SQLITE_NOMEM;
  return db->errCode;
}

/*
** Check schema cookies in all databases except TEMP.  If any cookie is out
** of date, return 0.  If all schema cookies are current, return 1.
*/
static int schemaIsValid(sqlite *db){
  int iDb;
  int rc;
  BtCursor *curTemp;
  int cookie;
  int allOk = 1;

  for(iDb=0; allOk && iDb<db->nDb; iDb++){
    Btree *pBt;
    if( iDb==1 ) continue;
    pBt = db->aDb[iDb].pBt;
    if( pBt==0 ) continue;
    rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
    if( rc==SQLITE_OK ){
      rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
      if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){
        allOk = 0;







|











<







918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936

937
938
939
940
941
942
943

int sqlite3_errcode(sqlite3 *db){
  if( !db ) return SQLITE_NOMEM;
  return db->errCode;
}

/*
** Check schema cookies in all databases.  If any cookie is out
** of date, return 0.  If all schema cookies are current, return 1.
*/
static int schemaIsValid(sqlite *db){
  int iDb;
  int rc;
  BtCursor *curTemp;
  int cookie;
  int allOk = 1;

  for(iDb=0; allOk && iDb<db->nDb; iDb++){
    Btree *pBt;

    pBt = db->aDb[iDb].pBt;
    if( pBt==0 ) continue;
    rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
    if( rc==SQLITE_OK ){
      rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
      if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){
        allOk = 0;
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.401 2004/07/18 21:33:02 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.402 2004/07/19 17:25:25 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
2359
2360
2361
2362
2363
2364
2365

2366


2367




2368
2369
2370
2371
2372
2373
2374
**
** 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;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );


  rc = sqlite3BtreeGetMeta(db->aDb[pOp->p1].pBt, 1, (u32 *)&iMeta);




  if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
    sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
    rc = SQLITE_SCHEMA;
  }
  break;
}








>

>
>
|
>
>
>
>







2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
**
** 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 );
  pBt = db->aDb[pOp->p1].pBt;
  if( pBt ){
    rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&iMeta);
  }else{
    rc = SQLITE_OK;
    iMeta = 0;
  }
  if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
    sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
    rc = SQLITE_SCHEMA;
  }
  break;
}

Changes to src/where.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.
**
** $Id: where.c,v 1.108 2004/07/19 02:12:14 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.
**
** $Id: where.c,v 1.109 2004/07/19 17:25:25 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
       pWInfo->a[0].bRev = bRev;
       *ppOrderBy = 0;
     }
  }

  /* Open all tables in the pTabList and all indices used by those tables.
  */
  sqlite3CodeVerifySchema(pParse, 1);  /* Inserts the cookie verifier Goto */
  for(i=0; i<pTabList->nSrc; i++){
    Table *pTab;
    Index *pIx;

    pTab = pTabList->a[i].pTab;
    if( pTab->isTransient || pTab->pSelect ) continue;
    sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);







|







691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
       pWInfo->a[0].bRev = bRev;
       *ppOrderBy = 0;
     }
  }

  /* Open all tables in the pTabList and all indices used by those tables.
  */
  sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
  for(i=0; i<pTabList->nSrc; i++){
    Table *pTab;
    Index *pIx;

    pTab = pTabList->a[i].pTab;
    if( pTab->isTransient || pTab->pSelect ) continue;
    sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
Changes to test/attach2.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.21 2004/06/21 18:14:47 drh Exp $
#

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


# Ticket #354







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.22 2004/07/19 17:25:25 drh Exp $
#

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


# Ticket #354
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  execsql {BEGIN}
  execsql {SELECT * FROM t1}
  # Lock status:
  #    db  - shared(main)
  #    db2 -
} {}

lock_status 4.2.1 db {main shared temp shared file2 unlocked}
lock_status 4.2.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.3 {
  # The read lock held by db does not prevent db2 from reading test.db
  execsql {SELECT * FROM t1} db2
} {}

lock_status 4.3.1 db {main shared temp shared file2 unlocked}
lock_status 4.3.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.4 {
  # db is holding a read lock on test.db, so we should not be able
  # to commit a write to test.db from db2
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  } db2 
} {1 {database is locked}}

lock_status 4.4.1 db {main shared temp shared file2 unlocked}
lock_status 4.4.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.5 {
  # Handle 'db2' reserves file2.
  execsql {BEGIN} db2
  execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
  # Lock status:
  #    db  - shared(main)
  #    db2 - reserved(file2)
} {}

lock_status 4.5.1 db {main shared temp shared file2 unlocked}
lock_status 4.5.2 db2 {main unlocked temp reserved file2 reserved}

do_test attach2-4.6.1 {
  # Reads are allowed against a reserved database.
  catchsql {
    SELECT * FROM file2.t1;
  }
  # Lock status:
  #    db  - shared(main), shared(file2)
  #    db2 - reserved(file2)
} {0 {}}

lock_status 4.6.1.1 db {main shared temp shared file2 shared}
lock_status 4.6.1.2 db2 {main unlocked temp reserved file2 reserved}

do_test attach2-4.6.2 {
  # Writes against a reserved database are not allowed.
  catchsql {
    UPDATE file2.t1 SET a=0;
  }







|







|










|











|












|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  execsql {BEGIN}
  execsql {SELECT * FROM t1}
  # Lock status:
  #    db  - shared(main)
  #    db2 -
} {}

lock_status 4.2.1 db {main shared temp unlocked file2 unlocked}
lock_status 4.2.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.3 {
  # The read lock held by db does not prevent db2 from reading test.db
  execsql {SELECT * FROM t1} db2
} {}

lock_status 4.3.1 db {main shared temp unlocked file2 unlocked}
lock_status 4.3.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.4 {
  # db is holding a read lock on test.db, so we should not be able
  # to commit a write to test.db from db2
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  } db2 
} {1 {database is locked}}

lock_status 4.4.1 db {main shared temp unlocked file2 unlocked}
lock_status 4.4.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.5 {
  # Handle 'db2' reserves file2.
  execsql {BEGIN} db2
  execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
  # Lock status:
  #    db  - shared(main)
  #    db2 - reserved(file2)
} {}

lock_status 4.5.1 db {main shared temp unlocked file2 unlocked}
lock_status 4.5.2 db2 {main unlocked temp reserved file2 reserved}

do_test attach2-4.6.1 {
  # Reads are allowed against a reserved database.
  catchsql {
    SELECT * FROM file2.t1;
  }
  # Lock status:
  #    db  - shared(main), shared(file2)
  #    db2 - reserved(file2)
} {0 {}}

lock_status 4.6.1.1 db {main shared temp unlocked file2 shared}
lock_status 4.6.1.2 db2 {main unlocked temp reserved file2 reserved}

do_test attach2-4.6.2 {
  # Writes against a reserved database are not allowed.
  catchsql {
    UPDATE file2.t1 SET a=0;
  }
Changes to test/join3.test.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for joins, including outer joins, where
# there are a large number of tables involved in the join.
#
# $Id: join3.test,v 1.1 2004/07/19 02:12:14 drh Exp $

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

# An unrestricted join
#
set result {}







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for joins, including outer joins, where
# there are a large number of tables involved in the join.
#
# $Id: join3.test,v 1.2 2004/07/19 17:25:25 drh Exp $

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

# An unrestricted join
#
set result {}
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    set sql "SELECT * FROM t1"
    for {set i 2} {$i<=$N} {incr i} {append sql ", t$i"}
    set sep WHERE
    for {set i 1} {$i<$N} {incr i} {
      append sql " $sep t[expr {$i+1}].x==t$i.x+1"
      set sep AND
    }
#if {$N==32} {btree_breakpoint}
#if {$N==33} {
#explain $sql
#execsql {PRAGMA vdbe_trace=on}
#}
    execsql $sql
  } $result
#if {$N==33} exit
}

finish_test







<
<
<
<
<


<



41
42
43
44
45
46
47





48
49

50
51
52
    set sql "SELECT * FROM t1"
    for {set i 2} {$i<=$N} {incr i} {append sql ", t$i"}
    set sep WHERE
    for {set i 1} {$i<$N} {incr i} {
      append sql " $sep t[expr {$i+1}].x==t$i.x+1"
      set sep AND
    }





    execsql $sql
  } $result

}

finish_test
Changes to test/misc4.test.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc4.test,v 1.2 2004/07/19 00:39:46 drh Exp $

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

# Prepare a statement that will create a temporary table.  Then do
# a rollback.  Then try to execute the prepared statement.
#







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc4.test,v 1.3 2004/07/19 17:25:25 drh Exp $

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

# Prepare a statement that will create a temporary table.  Then do
# a rollback.  Then try to execute the prepared statement.
#
37
38
39
40
41
42
43










44

45
46
    ROLLBACK;
  }
  sqlite3_step $stmt
  execsql {
    SELECT * FROM temp.t2;
  }
} {1}










catch {sqlite3_finalize $stmt}


finish_test







>
>
>
>
>
>
>
>
>
>
|
>


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    ROLLBACK;
  }
  sqlite3_step $stmt
  execsql {
    SELECT * FROM temp.t2;
  }
} {1}

# Drop the temporary table, then rerun the prepared  statement to
# recreate it again.  This recreates ticket #807.
#
do_test misc4-1.2 {
  execsql {DROP TABLE t2}
  sqlite3_reset $stmt
  sqlite3_step $stmt
} {SQLITE_ERROR}
do_test misc4-1.3 {
  sqlite3_finalize $stmt
} {SQLITE_SCHEMA}

finish_test
Changes to test/tclsqlite.test.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# Actually, all tests are based on the TCL interface, so the main
# interface is pretty well tested.  This file contains some addition
# tests for fringe issues that the main test suite does not cover.
#
# $Id: tclsqlite.test,v 1.26 2004/06/29 12:39:08 drh Exp $

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

# Check the error messages generated by tclsqlite
#
if {[sqlite3 -has-codec]} {







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# Actually, all tests are based on the TCL interface, so the main
# interface is pretty well tested.  This file contains some addition
# tests for fringe issues that the main test suite does not cover.
#
# $Id: tclsqlite.test,v 1.27 2004/07/19 17:25:25 drh Exp $

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

# Check the error messages generated by tclsqlite
#
if {[sqlite3 -has-codec]} {
129
130
131
132
133
134
135

136
137
138
139
140
141
142
do_test tcl-1.19 {
  set v [catch {db total_changes xyz} msg]
  lappend v $msg
} {1 {wrong # args: should be "db total_changes "}}


if {[sqlite3 -tcl-uses-utf]} {

  do_test tcl-2.1 {
    execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)"
    execsql "PRAGMA table_info(t\u0123x)"
  } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0"
  do_test tcl-2.2 {
    execsql "INSERT INTO t\u0123x VALUES(1,2.3)"
    db eval "SELECT * FROM t\u0123x" result break







>







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
do_test tcl-1.19 {
  set v [catch {db total_changes xyz} msg]
  lappend v $msg
} {1 {wrong # args: should be "db total_changes "}}


if {[sqlite3 -tcl-uses-utf]} {
  catch {unset ::result}
  do_test tcl-2.1 {
    execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)"
    execsql "PRAGMA table_info(t\u0123x)"
  } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0"
  do_test tcl-2.2 {
    execsql "INSERT INTO t\u0123x VALUES(1,2.3)"
    db eval "SELECT * FROM t\u0123x" result break