/ Check-in [b8ed812c]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Replace OP_Begin, OP_Commit and OP_Rollback with OP_AutoCommit. (CVS 1500)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b8ed812c92f2dbb4431d45aeb41646ceb53e0cbc
User & Date: danielk1977 2004-05-31 08:26:49
Context
2004-05-31
08:55
Remove the <ON CONFLICT> clause from BEGIN (CVS 1501) check-in: 9029274b user: danielk1977 tags: trunk
08:26
Replace OP_Begin, OP_Commit and OP_Rollback with OP_AutoCommit. (CVS 1500) check-in: b8ed812c user: danielk1977 tags: trunk
2004-05-30
21:14
Add 3-byte and 6-byte integer serial types. This makes databases smaller and faster. Should we go ahead and add 5- and 7-byte integer types too? (CVS 1499) check-in: e6685af8 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
4179
4180
4181
4182
4183
4184
4185














** 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.
**
*************************************************************************
** $Id: btree.c,v 1.152 2004/05/30 20:46:09 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
    rc = sqlite3pager_truncate(pBtTo->pPager, nPage);
  }
  if( rc ){
    sqlite3BtreeRollback(pBtTo);
  }
  return rc;  
}





















|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.153 2004/05/31 08:26:49 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
    rc = sqlite3pager_truncate(pBtTo->pPager, nPage);
  }
  if( rc ){
    sqlite3BtreeRollback(pBtTo);
  }
  return rc;  
}

/*
** Return non-zero if a transaction is active.
*/
int sqlite3BtreeIsInTrans(Btree *pBt){
  return (pBt && pBt->inTrans);
}

/*
** Return non-zero if a statement transaction is active.
*/
int sqlite3BtreeIsInStmt(Btree *pBt){
  return (pBt && pBt->inStmt);
}

Changes to src/btree.h.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
44
45
46
47
48
49
50


51
52
53
54
55
56
57
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite B-Tree file
** subsystem.  See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.49 2004/05/30 20:46:09 drh Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_

/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/
................................................................................
int sqlite3BtreeBeginTrans(Btree*);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*);
int sqlite3BtreeCommitStmt(Btree*);
int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);



const char *sqlite3BtreeGetFilename(Btree *);
int sqlite3BtreeCopyFile(Btree *, Btree *);

/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
** of the following flags:
*/







|







 







>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite B-Tree file
** subsystem.  See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.50 2004/05/31 08:26:49 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_

/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/
................................................................................
int sqlite3BtreeBeginTrans(Btree*);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*);
int sqlite3BtreeCommitStmt(Btree*);
int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);

const char *sqlite3BtreeGetFilename(Btree *);
int sqlite3BtreeCopyFile(Btree *, Btree *);

/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
** of the following flags:
*/

Changes to src/build.c.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
916
917
918
919
920
921
922









923
924
925
926
927
928
929
930

931
932
933
934
935
936
937
....
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
....
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
....
2161
2162
2163
2164
2165
2166
2167

2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179



2180

2181
2182
2183
2184
2185
2186
2187

2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201



2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
....
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271



2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
....
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.200 2004/05/29 11:24:50 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
................................................................................
** This plan is not completely bullet-proof.  It is possible for
** the schema to change multiple times and for the cookie to be
** set back to prior value.  But schema changes are infrequent
** and the probability of hitting the same cookie value is only
** 1 chance in 2^32.  So we're safe enough.
*/
void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){









  if( db->next_cookie==db->aDb[0].schema_cookie ){
    unsigned char r;
    sqlite3Randomness(1, &r);
    db->next_cookie = db->aDb[0].schema_cookie + r + 1;
    db->flags |= SQLITE_InternChanges;
    sqlite3VdbeAddOp(v, OP_Integer, db->next_cookie, 0);
    sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
  }

}

/*
** Measure the number of characters needed to output the given
** identifier.  The number returned includes any quotes used
** but does not include the null terminator.
*/
................................................................................
      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_Concat, 2, 0);
    }
    sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
    sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
    if( !p->iDb ){
      sqlite3ChangeCookie(db, v, p->iDb);
    }
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    if( pSelect ){
      sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
      sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
      pParse->nTab = 2;
................................................................................
  ** has just been created, it contains no data and the index initialization
  ** step can be skipped.
  */
  else if( db->init.busy==0 ){
    int n;
    Vdbe *v;
    int lbl1, lbl2;
    int i;

    v = sqlite3GetVdbe(pParse);
    if( v==0 ) goto exit_create_index;
    if( pTblName!=0 ){
      sqlite3BeginWriteOperation(pParse, 0, iDb);
      sqlite3OpenMasterTable(v, iDb);
    }
................................................................................
}

/*
** Begin a transaction
*/
void sqlite3BeginTransaction(Parse *pParse, int onError){
  sqlite *db;


  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
  if( pParse->nErr || sqlite3_malloc_failed ) return;
  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
  if( db->flags & SQLITE_InTrans ){
    sqlite3ErrorMsg(pParse, "cannot start a transaction within a transaction");
    return;
  }
  sqlite3BeginWriteOperation(pParse, 0, 0);
  if( !pParse->explain ){
    db->flags |= SQLITE_InTrans;
    db->onError = onError;



  }

}

/*
** Commit a transaction
*/
void sqlite3CommitTransaction(Parse *pParse){
  sqlite *db;


  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
  if( pParse->nErr || sqlite3_malloc_failed ) return;
  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqlite3ErrorMsg(pParse, "cannot commit - no transaction is active");
    return;
  }
  if( !pParse->explain ){
    db->flags &= ~SQLITE_InTrans;
  }
  sqlite3EndWriteOperation(pParse);
  if( !pParse->explain ){
    db->onError = OE_Default;



  }
}

/*
** Rollback a transaction
*/
void sqlite3RollbackTransaction(Parse *pParse){
  sqlite *db;
  Vdbe *v;

  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
  if( pParse->nErr || sqlite3_malloc_failed ) return;
  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqlite3ErrorMsg(pParse, "cannot rollback - no transaction is active");
    return; 
  }
  v = sqlite3GetVdbe(pParse);
  if( v ){
    sqlite3VdbeAddOp(v, OP_Rollback, 0, 0);
  }
  if( !pParse->explain ){
    db->flags &= ~SQLITE_InTrans;
    db->onError = OE_Default;
  }
}

/*
** Generate VDBE code that will verify the schema cookie for all
** named database files.
*/
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
  sqlite *db = pParse->db;
  Vdbe *v = sqlite3GetVdbe(pParse);
  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pBt!=0 );
  if( iDb!=1 && !DbHasProperty(db, iDb, DB_Cookie) ){
    sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
    DbSetProperty(db, iDb, DB_Cookie);
  }
}

/*
** Generate VDBE code that prepares for doing an operation that
** might change the database.
**
................................................................................
**
** Only database iDb and the temp database are made writable by this call.
** If iDb==0, then the main and temp databases are made writable.   If
** iDb==1 then only the temp database is made writable.  If iDb>1 then the
** specified auxiliary database and the temp database are made writable.
*/
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
  Vdbe *v;
  sqlite *db = pParse->db;
  if( DbHasProperty(db, iDb, DB_Locked) ) return;
  v = sqlite3GetVdbe(pParse);
  if( v==0 ) return;
  if( !db->aDb[iDb].inTrans ){
    sqlite3VdbeAddOp(v, OP_Transaction, iDb, 0);
    DbSetProperty(db, iDb, DB_Locked);
    sqlite3CodeVerifySchema(pParse, iDb);



    if( iDb!=1 ){
      sqlite3BeginWriteOperation(pParse, setStatement, 1);
    }
  }else if( setStatement ){
    sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
    DbSetProperty(db, iDb, DB_Locked);
  }
}

/*
** Generate code that concludes an operation that may have changed
** the database.  If a statement transaction was started, then emit
** an OP_Commit that will cause the changes to be committed to disk.
................................................................................
**
** Note that checkpoints are automatically committed at the end of
** a statement.  Note also that there can be multiple calls to 
** sqlite3BeginWriteOperation() but there should only be a single
** call to sqlite3EndWriteOperation() at the conclusion of the statement.
*/
void sqlite3EndWriteOperation(Parse *pParse){
  Vdbe *v;
  sqlite *db = pParse->db;
  if( pParse->trigStack ) return; /* if this is in a trigger */
  v = sqlite3GetVdbe(pParse);
  if( v==0 ) return;
  if( db->flags & SQLITE_InTrans ){
    /* A BEGIN has executed.  Do not commit until we see an explicit
    ** COMMIT statement. */
  }else{
    sqlite3VdbeAddOp(v, OP_Commit, 0, 0);
  }
}







|







 







>
>
>
>
>
>
>
>
>








>







 







|







 







<







 







>




<
<
<
|
<
<
<
<
>
>
>
|
>







>




<
<
<
|
<
<
<
<
<
<
>
>
>













<
<
<
|


|
<
<
<
<












|

|







 







<
<
<
|

<
|
<
|
>
>
>
|
|
<
<
<
<







 







|
<
<
<
|
<
<
<
<
<
|
<
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
916
917
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
945
946
947
....
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
....
1836
1837
1838
1839
1840
1841
1842

1843
1844
1845
1846
1847
1848
1849
....
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181



2182




2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199



2200






2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216



2217
2218
2219
2220




2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
....
2251
2252
2253
2254
2255
2256
2257



2258
2259

2260

2261
2262
2263
2264
2265
2266




2267
2268
2269
2270
2271
2272
2273
....
2274
2275
2276
2277
2278
2279
2280
2281



2282





2283

**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.201 2004/05/31 08:26:49 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
................................................................................
** This plan is not completely bullet-proof.  It is possible for
** the schema to change multiple times and for the cookie to be
** set back to prior value.  But schema changes are infrequent
** and the probability of hitting the same cookie value is only
** 1 chance in 2^32.  So we're safe enough.
*/
void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){
  unsigned char r;
  int *pSchemaCookie = &(db->aDb[iDb].schema_cookie);

  sqlite3Randomness(1, &r);
  *pSchemaCookie = *pSchemaCookie + r + 1;
  db->flags |= SQLITE_InternChanges;
  sqlite3VdbeAddOp(v, OP_Integer, *pSchemaCookie, 0);
  sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
/*
  if( db->next_cookie==db->aDb[0].schema_cookie ){
    unsigned char r;
    sqlite3Randomness(1, &r);
    db->next_cookie = db->aDb[0].schema_cookie + r + 1;
    db->flags |= SQLITE_InternChanges;
    sqlite3VdbeAddOp(v, OP_Integer, db->next_cookie, 0);
    sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
  }
*/
}

/*
** Measure the number of characters needed to output the given
** identifier.  The number returned includes any quotes used
** but does not include the null terminator.
*/
................................................................................
      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_Concat, 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);
    if( pSelect ){
      sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
      sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
      pParse->nTab = 2;
................................................................................
  ** has just been created, it contains no data and the index initialization
  ** step can be skipped.
  */
  else if( db->init.busy==0 ){
    int n;
    Vdbe *v;
    int lbl1, lbl2;


    v = sqlite3GetVdbe(pParse);
    if( v==0 ) goto exit_create_index;
    if( pTblName!=0 ){
      sqlite3BeginWriteOperation(pParse, 0, iDb);
      sqlite3OpenMasterTable(v, iDb);
    }
................................................................................
}

/*
** Begin a transaction
*/
void sqlite3BeginTransaction(Parse *pParse, int onError){
  sqlite *db;
  Vdbe *v;

  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
  if( pParse->nErr || sqlite3_malloc_failed ) return;
  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;








  v = sqlite3GetVdbe(pParse);
  if( !v ) return;
  sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0);

  /* FIX ME: Need to deal with onError */
}

/*
** Commit a transaction
*/
void sqlite3CommitTransaction(Parse *pParse){
  sqlite *db;
  Vdbe *v;

  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
  if( pParse->nErr || sqlite3_malloc_failed ) return;
  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;










  v = sqlite3GetVdbe(pParse);
  if( v ){
    sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0);
  }
}

/*
** Rollback a transaction
*/
void sqlite3RollbackTransaction(Parse *pParse){
  sqlite *db;
  Vdbe *v;

  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
  if( pParse->nErr || sqlite3_malloc_failed ) return;
  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;




  v = sqlite3GetVdbe(pParse);
  if( v ){
    sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1);




  }
}

/*
** Generate VDBE code that will verify the schema cookie for all
** named database files.
*/
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
  sqlite *db = pParse->db;
  Vdbe *v = sqlite3GetVdbe(pParse);
  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pBt!=0 );
  if( iDb!=1 && (iDb>63 || !(pParse->cookieMask & ((u64)1<<iDb))) ){
    sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
    pParse->cookieMask |= ((u64)1<<iDb);
  }
}

/*
** Generate VDBE code that prepares for doing an operation that
** might change the database.
**
................................................................................
**
** Only database iDb and the temp database are made writable by this call.
** If iDb==0, then the main and temp databases are made writable.   If
** iDb==1 then only the temp database is made writable.  If iDb>1 then the
** specified auxiliary database and the temp database are made writable.
*/
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){



  Vdbe *v = sqlite3GetVdbe(pParse);
  if( v==0 ) return;

  sqlite3VdbeAddOp(v, OP_Transaction, iDb, 0);

  sqlite3CodeVerifySchema(pParse, iDb);
  if( setStatement ){
    sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
  }
  if( iDb!=1 ){
    sqlite3BeginWriteOperation(pParse, setStatement, 1);




  }
}

/*
** Generate code that concludes an operation that may have changed
** the database.  If a statement transaction was started, then emit
** an OP_Commit that will cause the changes to be committed to disk.
................................................................................
**
** Note that checkpoints are automatically committed at the end of
** a statement.  Note also that there can be multiple calls to 
** sqlite3BeginWriteOperation() but there should only be a single
** call to sqlite3EndWriteOperation() at the conclusion of the statement.
*/
void sqlite3EndWriteOperation(Parse *pParse){
  /* Delete me! */



  return;





}

Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
1016
1017
1018
1019
1020
1021
1022

1023
1024
1025
1026
1027
1028
1029
**
*************************************************************************
** 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.196 2004/05/29 10:23:19 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information
................................................................................
  if( db==0 ) goto opendb_out;
  db->onError = OE_Default;
  db->priorNewRowid = 0;
  db->magic = SQLITE_MAGIC_BUSY;
  db->nDb = 2;
  db->aDb = db->aDbStatic;
  db->enc = def_enc;

  /* db->flags |= SQLITE_ShortColNames; */
  sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
  sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
  for(i=0; i<db->nDb; i++){
    sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
    sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
    sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);







|







 







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
**
*************************************************************************
** 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.197 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information
................................................................................
  if( db==0 ) goto opendb_out;
  db->onError = OE_Default;
  db->priorNewRowid = 0;
  db->magic = SQLITE_MAGIC_BUSY;
  db->nDb = 2;
  db->aDb = db->aDbStatic;
  db->enc = def_enc;
  db->autoCommit = 1;
  /* db->flags |= SQLITE_ShortColNames; */
  sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
  sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
  for(i=0; i<db->nDb; i++){
    sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
    sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
    sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.108 2004/05/14 01:58:13 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
** but if the operating system crashes or there is an abrupt power 
** failure, the database file might be left in an inconsistent and
** unrepairable state.  
*/
void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
  if( mxPage>=0 ){
    pPager->noSync = pPager->tempFile;
    if( pPager->noSync==0 ) pPager->needSync = 0;
  }else{
    pPager->noSync = 1;
    mxPage = -mxPage;
  }
  if( mxPage>10 ){
    pPager->mxPage = mxPage;
  }
................................................................................
**
** Numeric values associated with these states are OFF==1, NORMAL=2,
** and FULL=3.
*/
void sqlite3pager_set_safety_level(Pager *pPager, int level){
  pPager->noSync =  level==1 || pPager->tempFile;
  pPager->fullSync = level==3 && !pPager->tempFile;
  if( pPager->noSync==0 ) pPager->needSync = 0;
}

/*
** Open a temporary file.  Write the name of the file into zName
** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.)  Write
** the file descriptor into *fd.  Return SQLITE_OK on success or some
** other error code if we fail.







|







 







|







 







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.109 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
** but if the operating system crashes or there is an abrupt power 
** failure, the database file might be left in an inconsistent and
** unrepairable state.  
*/
void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
  if( mxPage>=0 ){
    pPager->noSync = pPager->tempFile;
    if( pPager->noSync ) pPager->needSync = 0; 
  }else{
    pPager->noSync = 1;
    mxPage = -mxPage;
  }
  if( mxPage>10 ){
    pPager->mxPage = mxPage;
  }
................................................................................
**
** Numeric values associated with these states are OFF==1, NORMAL=2,
** and FULL=3.
*/
void sqlite3pager_set_safety_level(Pager *pPager, int level){
  pPager->noSync =  level==1 || pPager->tempFile;
  pPager->fullSync = level==3 && !pPager->tempFile;
  if( pPager->noSync ) pPager->needSync = 0;
}

/*
** Open a temporary file.  Write the name of the file into zName
** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.)  Write
** the file descriptor into *fd.  Return SQLITE_OK on success or some
** other error code if we fail.

Changes to src/pragma.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
**    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 contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.34 2004/05/29 11:24:50 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Interpret the given string as a boolean value.
*/
................................................................................
** or DEFAULT_TEMP_STORE pragmas.
*/
static int changeTempStorage(Parse *pParse, const char *zStorageType){
  int ts = getTempStore(zStorageType);
  sqlite *db = pParse->db;
  if( db->temp_store==ts ) return SQLITE_OK;
  if( db->aDb[1].pBt!=0 ){
    if( db->flags & SQLITE_InTrans ){
      sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
        "from within a transaction");
      return SQLITE_ERROR;
    }
    sqlite3BtreeClose(db->aDb[1].pBt);
    db->aDb[1].pBt = 0;
    sqlite3ResetInternalSchema(db, 0);







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
**    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 contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.35 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Interpret the given string as a boolean value.
*/
................................................................................
** or DEFAULT_TEMP_STORE pragmas.
*/
static int changeTempStorage(Parse *pParse, const char *zStorageType){
  int ts = getTempStore(zStorageType);
  sqlite *db = pParse->db;
  if( db->temp_store==ts ) return SQLITE_OK;
  if( db->aDb[1].pBt!=0 ){
    if( !db->autoCommit ){
      sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
        "from within a transaction");
      return SQLITE_ERROR;
    }
    sqlite3BtreeClose(db->aDb[1].pBt);
    db->aDb[1].pBt = 0;
    sqlite3ResetInternalSchema(db, 0);

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
385
386
387
388
389
390
391

392
393
394
395
396
397
398
...
402
403
404
405
406
407
408

409
410
411
412
413
414
415
...
985
986
987
988
989
990
991

992
993
994
995
996
997
998
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.261 2004/05/29 02:37:19 danielk1977 Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "parse.h"
#include <stdio.h>
#include <stdlib.h>
................................................................................
  int csChange;                 /* Current statement change count (see above) */
  struct sqlite3InitInfo {       /* Information used during initialization */
    int iDb;                       /* When back is being initialized */
    int newTnum;                   /* Rootpage of table being initialized */
    u8 busy;                       /* TRUE if currently initializing */
  } init;
  struct Vdbe *pVdbe;           /* List of active virtual machines */

  void (*xTrace)(void*,const char*);     /* Trace function */
  void *pTraceArg;                       /* Argument to the trace function */
#ifndef SQLITE_OMIT_AUTHORIZATION
  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
                                /* Access authorization function */
  void *pAuthArg;               /* 1st argument to the access auth function */
#endif
................................................................................
  int nProgressOps;             /* Number of opcodes for progress callback */
#endif

  int errCode;                  /* Most recent error code (SQLITE_*) */
  char *zErrMsg;                /* Most recent error message (UTF-8 encoded) */
  void *zErrMsg16;              /* Most recent error message (UTF-16 encoded) */
  u8 enc;                       /* Text encoding for this database. */

};

/*
** Possible values for the sqlite.flags and or Db.flags fields.
**
** On sqlite.flags, the SQLITE_InTrans value means that we have
** executed a BEGIN.  On Db.flags, SQLITE_InTrans means a statement
................................................................................
  int nSet;            /* Number of sets used so far */
  int nAgg;            /* Number of aggregate expressions */
  int nVar;            /* Number of '?' variables seen in the SQL so far */
  AggExpr *aAgg;       /* An array of aggregate expressions */
  const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
  Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
  TriggerStack *trigStack;  /* Trigger actions being coded */

};

/*
** An instance of the following structure can be declared on a stack and used
** to save the Parse.zAuthContext value so that it can be restored later.
*/
struct AuthContext {







|







 







>







 







>







 







>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
...
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
...
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.262 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "parse.h"
#include <stdio.h>
#include <stdlib.h>
................................................................................
  int csChange;                 /* Current statement change count (see above) */
  struct sqlite3InitInfo {       /* Information used during initialization */
    int iDb;                       /* When back is being initialized */
    int newTnum;                   /* Rootpage of table being initialized */
    u8 busy;                       /* TRUE if currently initializing */
  } init;
  struct Vdbe *pVdbe;           /* List of active virtual machines */
  int activeVdbeCnt;            /* Number of vdbes currently executing */
  void (*xTrace)(void*,const char*);     /* Trace function */
  void *pTraceArg;                       /* Argument to the trace function */
#ifndef SQLITE_OMIT_AUTHORIZATION
  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
                                /* Access authorization function */
  void *pAuthArg;               /* 1st argument to the access auth function */
#endif
................................................................................
  int nProgressOps;             /* Number of opcodes for progress callback */
#endif

  int errCode;                  /* Most recent error code (SQLITE_*) */
  char *zErrMsg;                /* Most recent error message (UTF-8 encoded) */
  void *zErrMsg16;              /* Most recent error message (UTF-16 encoded) */
  u8 enc;                       /* Text encoding for this database. */
  u8 autoCommit;                /* The auto-commit flag. */
};

/*
** Possible values for the sqlite.flags and or Db.flags fields.
**
** On sqlite.flags, the SQLITE_InTrans value means that we have
** executed a BEGIN.  On Db.flags, SQLITE_InTrans means a statement
................................................................................
  int nSet;            /* Number of sets used so far */
  int nAgg;            /* Number of aggregate expressions */
  int nVar;            /* Number of '?' variables seen in the SQL so far */
  AggExpr *aAgg;       /* An array of aggregate expressions */
  const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
  Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
  TriggerStack *trigStack;  /* Trigger actions being coded */
  u64 cookieMask;      /* Bitmask of schema verified databases */
};

/*
** An instance of the following structure can be declared on a stack and used
** to save the Parse.zAuthContext value so that it can be restored later.
*/
struct AuthContext {

Changes to src/test3.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
180
181
182
183
184
185
186

















































































187
188
189
190
191
192
193
....
1253
1254
1255
1256
1257
1258
1259



1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the btree.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test3.c,v 1.39 2004/05/30 20:46:09 drh Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
#include "btree.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
................................................................................
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID\"", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
  rc = sqlite3BtreeCommit(pBt);

















































































  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}

................................................................................
     { "btree_first",              (Tcl_CmdProc*)btree_first              },
     { "btree_last",               (Tcl_CmdProc*)btree_last               },
     { "btree_cursor_info",        (Tcl_CmdProc*)btree_cursor_info        },
     { "btree_cursor_list",        (Tcl_CmdProc*)btree_cursor_list        },
     { "btree_integrity_check",    (Tcl_CmdProc*)btree_integrity_check    },
     { "btree_breakpoint",         (Tcl_CmdProc*)btree_breakpoint         },
     { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },



  };
  int i;

  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }
  Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable,
     TCL_LINK_INT);
  Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace,
     TCL_LINK_INT);
  return TCL_OK;
}







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>












9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
....
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the btree.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test3.c,v 1.40 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
#include "btree.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
................................................................................
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID\"", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
  rc = sqlite3BtreeCommit(pBt);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*
** Usage:   btree_begin_statement ID
**
** Start a new statement transaction
*/
static int btree_begin_statement(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  Btree *pBt;
  int rc;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID\"", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
  rc = sqlite3BtreeBeginStmt(pBt);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*
** Usage:   btree_rollback_statement ID
**
** Rollback changes
*/
static int btree_rollback_statement(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  Btree *pBt;
  int rc;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID\"", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
  rc = sqlite3BtreeRollbackStmt(pBt);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}

/*
** Usage:   btree_commit_statement ID
**
** Commit all changes
*/
static int btree_commit_statement(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  Btree *pBt;
  int rc;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID\"", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
  rc = sqlite3BtreeCommitStmt(pBt);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}

................................................................................
     { "btree_first",              (Tcl_CmdProc*)btree_first              },
     { "btree_last",               (Tcl_CmdProc*)btree_last               },
     { "btree_cursor_info",        (Tcl_CmdProc*)btree_cursor_info        },
     { "btree_cursor_list",        (Tcl_CmdProc*)btree_cursor_list        },
     { "btree_integrity_check",    (Tcl_CmdProc*)btree_integrity_check    },
     { "btree_breakpoint",         (Tcl_CmdProc*)btree_breakpoint         },
     { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },
     { "btree_begin_statement",    (Tcl_CmdProc*)btree_begin_statement    },
     { "btree_commit_statement",   (Tcl_CmdProc*)btree_commit_statement   },
     { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
  };
  int i;

  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }
  Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable,
     TCL_LINK_INT);
  Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace,
     TCL_LINK_INT);
  return TCL_OK;
}

Changes to src/trigger.c.

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
...
707
708
709
710
711
712
713

714
715
716
717
718
719
720
...
778
779
780
781
782
783
784

785
786
787
788
789
    if( v==0 ) goto triggerfinish_cleanup;
    sqlite3BeginWriteOperation(pParse, 0, nt->iDb);
    sqlite3OpenMasterTable(v, nt->iDb);
    addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
    sqlite3VdbeChangeP3(v, addr+2, nt->name, 0); 
    sqlite3VdbeChangeP3(v, addr+3, nt->table, 0); 
    sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
    if( nt->iDb==0 ){
      sqlite3ChangeCookie(db, v, 0);
    }
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    sqlite3EndWriteOperation(pParse);
  }

  if( !pParse->explain ){
    Table *pTab;
................................................................................
      { OP_Next,       0, ADDR(1),  0}, /* 8 */
    };

    sqlite3BeginWriteOperation(pParse, 0, pTrigger->iDb);
    sqlite3OpenMasterTable(v, pTrigger->iDb);
    base = sqlite3VdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
    sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
    if( pTrigger->iDb==0 ){
      sqlite3ChangeCookie(db, v, 0);
    }
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    sqlite3EndWriteOperation(pParse);
  }

  /*
   * If this is not an "explain", then delete the trigger structure.
................................................................................
  int newIdx,          /* The indice of the "new" row to access */
  int oldIdx,          /* The indice of the "old" row to access */
  int orconf,          /* ON CONFLICT policy */
  int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
){
  Trigger * pTrigger;
  TriggerStack * pTriggerStack;


  assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
  assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );

  assert(newIdx != -1 || oldIdx != -1);

  pTrigger = pTab->pTrigger;
................................................................................
      sqliteFree(pTriggerStack);

      sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
    }
    pTrigger = pTrigger->pNext;
  }


  return 0;
}










|
|







 







|
|







 







>







 







>





227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
...
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
...
779
780
781
782
783
784
785
786
787
788
789
790
791
    if( v==0 ) goto triggerfinish_cleanup;
    sqlite3BeginWriteOperation(pParse, 0, nt->iDb);
    sqlite3OpenMasterTable(v, nt->iDb);
    addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
    sqlite3VdbeChangeP3(v, addr+2, nt->name, 0); 
    sqlite3VdbeChangeP3(v, addr+3, nt->table, 0); 
    sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
    if( nt->iDb!=0 ){
      sqlite3ChangeCookie(db, v, nt->iDb);
    }
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    sqlite3EndWriteOperation(pParse);
  }

  if( !pParse->explain ){
    Table *pTab;
................................................................................
      { OP_Next,       0, ADDR(1),  0}, /* 8 */
    };

    sqlite3BeginWriteOperation(pParse, 0, pTrigger->iDb);
    sqlite3OpenMasterTable(v, pTrigger->iDb);
    base = sqlite3VdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
    sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
    if( pTrigger->iDb!=1 ){
      sqlite3ChangeCookie(db, v, pTrigger->iDb);
    }
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    sqlite3EndWriteOperation(pParse);
  }

  /*
   * If this is not an "explain", then delete the trigger structure.
................................................................................
  int newIdx,          /* The indice of the "new" row to access */
  int oldIdx,          /* The indice of the "old" row to access */
  int orconf,          /* ON CONFLICT policy */
  int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
){
  Trigger * pTrigger;
  TriggerStack * pTriggerStack;
  u64 cookieMask = pParse->cookieMask;

  assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
  assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );

  assert(newIdx != -1 || oldIdx != -1);

  pTrigger = pTab->pTrigger;
................................................................................
      sqliteFree(pTriggerStack);

      sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
    }
    pTrigger = pTrigger->pNext;
  }

  pParse->cookieMask = cookieMask;
  return 0;
}



Changes to src/vacuum.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110
...
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
232
**
*************************************************************************
** This file contains code used to implement the VACUUM command.
**
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.18 2004/05/29 10:43:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"

#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
................................................................................
int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){
  int rc = SQLITE_OK;     /* Return code from service routines */
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
  const char *zFilename;  /* full pathname of the database file */
  int nFilename;          /* number of characters  in zFilename[] */
  char *zTemp = 0;        /* a temporary file in same directory as zFilename */
  int i;                  /* Loop counter */


  char *zSql = 0;
  sqlite3_stmt *pStmt = 0;

  if( db->flags & SQLITE_InTrans ){
    sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", 
       (char*)0);
    rc = SQLITE_ERROR;
    goto end_of_vacuum;
  }

  /* Get the full pathname of the database file and create a
................................................................................
  ** transaction open on the vacuum database, but not on the main database.
  ** Open a btree level transaction on the main database. This allows a
  ** call to sqlite3BtreeCopyFile(). The main database btree level
  ** transaction is then committed, so the SQL level never knows it was
  ** opened for writing. This way, the SQL transaction used to create the
  ** temporary database never needs to be committed.
  */





  /* FIX ME: The above will be the case shortly. But for now, a transaction
  ** will have been started on the main database file by the 'BEGIN'.
  */
/*

  rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt);
  if( rc!=SQLITE_OK ) goto end_of_vacuum;
*/

  if( db->aDb[db->nDb-1].inTrans ){
    Btree *pTemp = db->aDb[db->nDb-1].pBt;
    Btree *pMain = db->aDb[0].pBt;
    u32 meta;

    /* Copy Btree meta values 3 and 4. These correspond to SQL layer meta 
    ** values 2 and 3, the default values of a couple of pragmas.
    */
    rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
................................................................................
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;

    rc = sqlite3BtreeCopyFile(pMain, pTemp);

    /* FIX ME: Remove the main btree from the transaction so that it is not
    ** rolled back. This won't be required once the new 'auto-commit'
    ** model is in place.
    */
    rc = sqlite3BtreeCommit(pMain);
    db->aDb[0].inTrans = 0;
  }

end_of_vacuum:
  execSql(db, "DETACH vacuum_db;");
  execSql(db, "ROLLBACK;");
  if( zTemp ){
    sqlite3OsDelete(zTemp);







|







 







>




|







 







>
>
>
>

<
<
<
<
>
|
|
<
<
<
<
<
<







 







<
<
<
<
<

<







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
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
**
*************************************************************************
** This file contains code used to implement the VACUUM command.
**
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.19 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"

#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
................................................................................
int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){
  int rc = SQLITE_OK;     /* Return code from service routines */
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
  const char *zFilename;  /* full pathname of the database file */
  int nFilename;          /* number of characters  in zFilename[] */
  char *zTemp = 0;        /* a temporary file in same directory as zFilename */
  int i;                  /* Loop counter */
  Btree *pTemp;

  char *zSql = 0;
  sqlite3_stmt *pStmt = 0;

  if( !db->autoCommit ){
    sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", 
       (char*)0);
    rc = SQLITE_ERROR;
    goto end_of_vacuum;
  }

  /* Get the full pathname of the database file and create a
................................................................................
  ** transaction open on the vacuum database, but not on the main database.
  ** Open a btree level transaction on the main database. This allows a
  ** call to sqlite3BtreeCopyFile(). The main database btree level
  ** transaction is then committed, so the SQL level never knows it was
  ** opened for writing. This way, the SQL transaction used to create the
  ** temporary database never needs to be committed.
  */
  pTemp = db->aDb[db->nDb-1].pBt;
  if( sqlite3BtreeIsInTrans(pTemp) ){
    Btree *pMain = db->aDb[0].pBt;
    u32 meta;





    assert( 0==sqlite3BtreeIsInTrans(pMain) );
    rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;







    /* Copy Btree meta values 3 and 4. These correspond to SQL layer meta 
    ** values 2 and 3, the default values of a couple of pragmas.
    */
    rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
................................................................................
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;

    rc = sqlite3BtreeCopyFile(pMain, pTemp);





    rc = sqlite3BtreeCommit(pMain);

  }

end_of_vacuum:
  execSql(db, "DETACH vacuum_db;");
  execSql(db, "ROLLBACK;");
  if( zTemp ){
    sqlite3OsDelete(zTemp);

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
2192
2193
2194
2195
2196
2197
2198

2199


2200
2201





























2202
2203
2204
2205
2206
2207
2208
....
2218
2219
2220
2221
2222
2223
2224


2225
2226
2227



2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
....
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
....
3564
3565
3566
3567
3568
3569
3570



3571
3572
3573
3574
3575
3576

3577
3578
3579
3580
3581
3582
3583
**
** 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.350 2004/05/30 21:14:59 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
**
** The statement is begun on the database file with index P1.  The main
** database file has an index of 0 and the file used for temporary tables
** has an index of 1.
*/
case OP_Statement: {
  int i = pOp->p1;

  if( i>=0 && i<db->nDb && db->aDb[i].pBt && db->aDb[i].inTrans==1 ){


    rc = sqlite3BtreeBeginStmt(db->aDb[i].pBt);
    if( rc==SQLITE_OK ) db->aDb[i].inTrans = 2;





























  }
  break;
}

/* Opcode: Transaction P1 * *
**
** Begin a transaction.  The transaction ends when a Commit or Rollback
................................................................................
** transaction is underway.  Starting a transaction also creates a
** rollback journal.  A transaction must be started before any changes
** can be made to the database.
*/
case OP_Transaction: {
  int busy = 1;
  int i = pOp->p1;


  assert( i>=0 && i<db->nDb );
  if( db->aDb[i].inTrans ) break;
  while( db->aDb[i].pBt!=0 && busy ){



    rc = sqlite3BtreeBeginTrans(db->aDb[i].pBt);
    switch( rc ){
      case SQLITE_BUSY: {
        if( db->xBusyCallback==0 ){
          p->pc = pc;
          p->undoTransOnError = 1;
          p->rc = SQLITE_BUSY;
          p->pTos = pTos;
          return SQLITE_BUSY;
        }else if( (*db->xBusyCallback)(db->pBusyArg, "", busy++)==0 ){
          sqlite3SetString(&p->zErrMsg, sqlite3_error_string(rc), (char*)0);
          busy = 0;
        }
................................................................................
        break;
      }
      case SQLITE_READONLY: {
        rc = SQLITE_OK;
        /* Fall thru into the next case */
      }
      case SQLITE_OK: {
        p->inTempTrans = 0;
        busy = 0;
        break;
      }
      default: {
        goto abort_due_to_error;
      }
    }
  }
  db->aDb[i].inTrans = 1;
  p->undoTransOnError = 1;
  break;
}

/* Opcode: Commit * * *
**
** Cause all modifications to the database that have been made since the
** last Transaction to actually take effect.  No additional modifications
** are allowed until another transaction is started.  The Commit instruction
** deletes the journal file and releases the write lock on the database.
** A read lock continues to be held if there are still cursors open.
*/
case OP_Commit: {
  int i;
  if( db->xCommitCallback!=0 ){
    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; 
    if( db->xCommitCallback(db->pCommitArg)!=0 ){
      rc = SQLITE_CONSTRAINT;
    }
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
  }
  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    if( db->aDb[i].inTrans ){
      rc = sqlite3BtreeCommit(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  if( rc==SQLITE_OK ){
    sqlite3CommitInternalChanges(db);
  }else{
    sqlite3RollbackAll(db);
  }
  break;
}

/* Opcode: Rollback P1 * *
**
** Cause all modifications to the database that have been made since the
** last Transaction to be undone. The database is restored to its state
** before the Transaction opcode was executed.  No additional modifications
** are allowed until another transaction is started.
**
** P1 is the index of the database file that is committed.  An index of 0
** is used for the main database and an index of 1 is used for the file used
** to hold temporary tables.
**
** This instruction automatically closes all cursors and releases both
** the read and write locks on the indicated database.
*/
case OP_Rollback: {
  sqlite3RollbackAll(db);
  break;
}

/* Opcode: ReadCookie P1 P2 *
**
** Read cookie number P2 from database P1 and push it onto the stack.
** P2==0 is the schema version.  P2==1 is the database format.
................................................................................
  assert( i>=0 && i<p->nCursor );
  pTos++;
  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
    i64 rowid;

    assert( pC->deferredMoveto==0 );
    assert( pC->intKey==0 );



    rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
    pTos->flags = MEM_Int;
    pTos->i = rowid;


#if 0
    /* Read the final 9 bytes of the key into buf[]. If the whole key is
    ** less than 9 bytes then just load the whole thing. Set len to the 
    ** number of bytes read.
    */
    sqlite3BtreeKeySize(pCrsr, &sz);







|







 







>
|
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>

<
|
>
>
>





<







 







<








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
|
|
|
|
|
|
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203

2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
....
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258

2259
2260
2261
2262
2263
2264
2265
2266
2267

2268
2269
2270
2271
2272
2273
2274
....
2275
2276
2277
2278
2279
2280
2281

2282
2283
2284
2285
2286
2287
2288
2289




















































2290
2291
2292
2293
2294
2295
2296
....
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
**
** 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.351 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
**
** The statement is begun on the database file with index P1.  The main
** database file has an index of 0 and the file used for temporary tables
** has an index of 1.
*/
case OP_Statement: {
  int i = pOp->p1;
  Btree *pBt;
  if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt) && !(db->autoCommit) ){
    assert( sqlite3BtreeIsInTrans(pBt) );
    if( !sqlite3BtreeIsInStmt(pBt) ){
      rc = sqlite3BtreeBeginStmt(pBt);

    }
  }
  break;
}

/* Opcode: AutoCommit P1 P2 *
**
** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
** back any currently active btree transactions.
*/
case OP_AutoCommit: {
  u8 i = pOp->p1;
  u8 rollback = pOp->p2;

  assert( i==1 || i==0 );
  assert( i==1 || rollback==0 );

  if( i!=db->autoCommit ){
    db->autoCommit = i;
    if( pOp->p2 ){
      sqlite3RollbackAll(db);
    }
  }else{
    sqlite3SetString(&p->zErrMsg,
        (!i)?"cannot start a transaction within a transaction":(
        (rollback)?"cannot rollback - no transaction is active":
                   "cannot commit - no transaction is active"), 0);
         
    rc = SQLITE_ERROR;
  }
  break;
}

/* Opcode: Transaction P1 * *
**
** Begin a transaction.  The transaction ends when a Commit or Rollback
................................................................................
** transaction is underway.  Starting a transaction also creates a
** rollback journal.  A transaction must be started before any changes
** can be made to the database.
*/
case OP_Transaction: {
  int busy = 1;
  int i = pOp->p1;
  Btree *pBt;

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

  pBt = db->aDb[i].pBt;

  if( sqlite3BtreeIsInTrans(pBt) ) break;
  while( pBt && busy /* && !sqlite3BtreeIsInTrans(pBt) */ ){
    rc = sqlite3BtreeBeginTrans(db->aDb[i].pBt);
    switch( rc ){
      case SQLITE_BUSY: {
        if( db->xBusyCallback==0 ){
          p->pc = pc;

          p->rc = SQLITE_BUSY;
          p->pTos = pTos;
          return SQLITE_BUSY;
        }else if( (*db->xBusyCallback)(db->pBusyArg, "", busy++)==0 ){
          sqlite3SetString(&p->zErrMsg, sqlite3_error_string(rc), (char*)0);
          busy = 0;
        }
................................................................................
        break;
      }
      case SQLITE_READONLY: {
        rc = SQLITE_OK;
        /* Fall thru into the next case */
      }
      case SQLITE_OK: {

        busy = 0;
        break;
      }
      default: {
        goto abort_due_to_error;
      }
    }
  }




















































  break;
}

/* Opcode: ReadCookie P1 P2 *
**
** Read cookie number P2 from database P1 and push it onto the stack.
** P2==0 is the schema version.  P2==1 is the database format.
................................................................................
  assert( i>=0 && i<p->nCursor );
  pTos++;
  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
    i64 rowid;

    assert( pC->deferredMoveto==0 );
    assert( pC->intKey==0 );
    if( pC->nullRow ){
      pTos->flags = MEM_Null;
    }else{
      rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pTos->flags = MEM_Int;
      pTos->i = rowid;
    }

#if 0
    /* Read the final 9 bytes of the key into buf[]. If the whole key is
    ** less than 9 bytes then just load the whole thing. Set len to the 
    ** number of bytes read.
    */
    sqlite3BtreeKeySize(pCrsr, &sz);

Changes to src/vdbeInt.h.

303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
  int contextStackDepth;  /* The size of the "context" stack */
  Context *contextStack;  /* Stack used by opcodes ContextPush & ContextPop*/
  int pc;                 /* The program counter */
  int rc;                 /* Value to return */
  unsigned uniqueCnt;     /* Used by OP_MakeRecord when P2!=0 */
  int errorAction;        /* Recovery action to do in case of an error */
  int undoTransOnError;   /* If error, either ROLLBACK or COMMIT */
  int inTempTrans;        /* True if temp database is transactioned */
  int returnStack[100];   /* Return address stack for OP_Gosub & OP_Return */
  int returnDepth;        /* Next unused element in returnStack[] */
  int nResColumn;         /* Number of columns in one row of the result set */
  char **azResColumn;     /* Values for one row of result */ 
  u8 resOnStack;          /* True if there are result values on the stack */
  int popStack;           /* Pop the stack this much on entry to VdbeExec() */







<







303
304
305
306
307
308
309

310
311
312
313
314
315
316
  Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
  int contextStackDepth;  /* The size of the "context" stack */
  Context *contextStack;  /* Stack used by opcodes ContextPush & ContextPop*/
  int pc;                 /* The program counter */
  int rc;                 /* Value to return */
  unsigned uniqueCnt;     /* Used by OP_MakeRecord when P2!=0 */
  int errorAction;        /* Recovery action to do in case of an error */

  int inTempTrans;        /* True if temp database is transactioned */
  int returnStack[100];   /* Return address stack for OP_Gosub & OP_Return */
  int returnDepth;        /* Next unused element in returnStack[] */
  int nResColumn;         /* Number of columns in one row of the result set */
  char **azResColumn;     /* Values for one row of result */ 
  u8 resOnStack;          /* True if there are result values on the stack */
  int popStack;           /* Pop the stack this much on entry to VdbeExec() */

Changes to src/vdbeapi.c.

163
164
165
166
167
168
169




170
171
172
173
174
175
176
...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  if( p->magic!=VDBE_MAGIC_RUN ){
    return SQLITE_MISUSE;
  }
  db = p->db;
  if( sqlite3SafetyOn(db) ){
    p->rc = SQLITE_MISUSE;
    return SQLITE_MISUSE;




  }
  if( p->explain ){
    rc = sqlite3VdbeList(p);
  }else{
    rc = sqlite3VdbeExec(p);
  }

................................................................................
** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
**
** The error code stored in database p->db is overwritten with the return
** value in any case.
*/
static int vdbeUnbind(Vdbe *p, int i){
  Mem *pVar;
  if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 ){
    sqlite3Error(p->db, SQLITE_MISUSE, 0);
    return SQLITE_MISUSE;
  }
  if( i<1 || i>p->nVar ){
    sqlite3Error(p->db, SQLITE_RANGE, 0);
    return SQLITE_RANGE;
  }







>
>
>
>







 







|







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  if( p->magic!=VDBE_MAGIC_RUN ){
    return SQLITE_MISUSE;
  }
  db = p->db;
  if( sqlite3SafetyOn(db) ){
    p->rc = SQLITE_MISUSE;
    return SQLITE_MISUSE;
  }
  if( p->pc<0 ){
    db->activeVdbeCnt++;
    p->pc = 0;
  }
  if( p->explain ){
    rc = sqlite3VdbeList(p);
  }else{
    rc = sqlite3VdbeExec(p);
  }

................................................................................
** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
**
** The error code stored in database p->db is overwritten with the return
** value in any case.
*/
static int vdbeUnbind(Vdbe *p, int i){
  Mem *pVar;
  if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
    sqlite3Error(p->db, SQLITE_MISUSE, 0);
    return SQLITE_MISUSE;
  }
  if( i<1 || i>p->nVar ){
    sqlite3Error(p->db, SQLITE_RANGE, 0);
    return SQLITE_RANGE;
  }

Changes to src/vdbeaux.c.

655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
...
892
893
894
895
896
897
898


























899
900
901
902
903
904
905
906
907
908


909
910
911
912

913
914
915
916
917
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
945
946
947

948
949
950
951
952
953


954
955
956
957


958
959
960
961
962
963
964


965

966
967
968
969
970
971
972
973
  p->agg.pSearch = 0;
#ifdef MEMORY_DEBUG
  if( sqlite3OsFileExists("vdbe_trace") ){
    p->trace = stdout;
  }
#endif
  p->pTos = &p->aStack[-1];
  p->pc = 0;
  p->rc = SQLITE_OK;
  p->uniqueCnt = 0;
  p->returnDepth = 0;
  p->errorAction = OE_Abort;
  p->undoTransOnError = 0;
  p->popStack =  0;
  p->explain |= isExplain;
  p->magic = VDBE_MAGIC_RUN;
#ifdef VDBE_PROFILE
  {
    int i;
    for(i=0; i<p->nOp; i++){
................................................................................
  }
  if( rc==SQLITE_OK && N==P3_DYNAMIC ){
    pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn;
  }
  return rc;
}



























/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg.  Return the result code.
**
** After this routine is run, the VDBE should be ready to be executed
** again.
*/
int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){
  sqlite *db = p->db;
  int i;



  if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
    sqlite3SetString(pzErrMsg, sqlite3_error_string(SQLITE_MISUSE), (char*)0);
    sqlite3Error(p->db, SQLITE_MISUSE, sqlite3_error_string(SQLITE_MISUSE),0);

    return SQLITE_MISUSE;
  }
  if( p->zErrMsg ){
    sqlite3Error(p->db, p->rc, "%s", p->zErrMsg, 0);
    if( pzErrMsg && *pzErrMsg==0 ){
      *pzErrMsg = p->zErrMsg;
    }else{
      sqliteFree(p->zErrMsg);
    }
    p->zErrMsg = 0;
  }else if( p->rc ){
    sqlite3SetString(pzErrMsg, sqlite3_error_string(p->rc), (char*)0);
    sqlite3Error(p->db, p->rc, "%s", sqlite3_error_string(p->rc) , 0);
  }else{
    sqlite3Error(p->db, SQLITE_OK, 0);
  }
  Cleanup(p);
  if( p->rc!=SQLITE_OK ){

    switch( p->errorAction ){
      case OE_Abort: {
        if( !p->undoTransOnError ){

          for(i=0; i<db->nDb; i++){
            if( db->aDb[i].pBt ){










              sqlite3BtreeRollbackStmt(db->aDb[i].pBt);



            }
          }
          break;
        }
        /* Fall through to ROLLBACK */









      }
      case OE_Rollback: {
        sqlite3RollbackAll(db);
        db->flags &= ~SQLITE_InTrans;
        db->onError = OE_Default;
        break;

      }
      default: {
        if( p->undoTransOnError ){
          sqlite3RollbackAll(db);
          db->flags &= ~SQLITE_InTrans;
          db->onError = OE_Default;


        }
        break;
      }
    }


    sqlite3RollbackInternalChanges(db);
  }
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt && db->aDb[i].inTrans==2 ){
      sqlite3BtreeCommitStmt(db->aDb[i].pBt);
      db->aDb[i].inTrans = 1;
    }


  }

  assert( p->pTos<&p->aStack[p->pc] || sqlite3_malloc_failed==1 );
#ifdef VDBE_PROFILE
  {
    FILE *out = fopen("vdbe_profile.out", "a");
    if( out ){
      int i;
      fprintf(out, "---- ");
      for(i=0; i<p->nOp; i++){







|




<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










>
>



|
>












|




<
>
|
|
<
>
|
|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
|
|
<
|
<
>
>
>
>
>
>
>
>
>
|
<
<
<
<
<
>

<
<
<
<
<
>
>
|
<
|
|
>
>


<
<
<
<
|
>
>

>
|







655
656
657
658
659
660
661
662
663
664
665
666

667
668
669
670
671
672
673
...
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
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
945
946
947
948
949
950
951
952
953
954
955
956
957

958
959
960

961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979

980

981
982
983
984
985
986
987
988
989
990





991
992





993
994
995

996
997
998
999
1000
1001




1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  p->agg.pSearch = 0;
#ifdef MEMORY_DEBUG
  if( sqlite3OsFileExists("vdbe_trace") ){
    p->trace = stdout;
  }
#endif
  p->pTos = &p->aStack[-1];
  p->pc = -1;
  p->rc = SQLITE_OK;
  p->uniqueCnt = 0;
  p->returnDepth = 0;
  p->errorAction = OE_Abort;

  p->popStack =  0;
  p->explain |= isExplain;
  p->magic = VDBE_MAGIC_RUN;
#ifdef VDBE_PROFILE
  {
    int i;
    for(i=0; i<p->nOp; i++){
................................................................................
  }
  if( rc==SQLITE_OK && N==P3_DYNAMIC ){
    pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn;
  }
  return rc;
}

/* 
** This routine checks that the sqlite3.activeVdbeCnt count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are
** currently active. An assertion fails if the two counts do not match.
**
** This is a no-op if NDEBUG is defined.
*/
#ifndef NDEBUG
static void checkActiveVdbeCnt(sqlite *db){
  Vdbe *p;
  int cnt = 0;

  p = db->pVdbe;
  while( p ){
    if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
      cnt++;
    }
    p = p->pNext;
  }

  assert( cnt==db->activeVdbeCnt );
}
#else
#define checkActiveVdbeCnt(x)
#endif

/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg.  Return the result code.
**
** After this routine is run, the VDBE should be ready to be executed
** again.
*/
int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){
  sqlite *db = p->db;
  int i;
  int (*xFunc)(Btree *pBt) = 0;  /* Function to call on each btree backend */
  int needXcommit = 0;

  if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
    sqlite3SetString(pzErrMsg, sqlite3_error_string(SQLITE_MISUSE), (char*)0);
    sqlite3Error(p->db, SQLITE_MISUSE, 0 ,0);
    db->activeVdbeCnt--;
    return SQLITE_MISUSE;
  }
  if( p->zErrMsg ){
    sqlite3Error(p->db, p->rc, "%s", p->zErrMsg, 0);
    if( pzErrMsg && *pzErrMsg==0 ){
      *pzErrMsg = p->zErrMsg;
    }else{
      sqliteFree(p->zErrMsg);
    }
    p->zErrMsg = 0;
  }else if( p->rc ){
    sqlite3SetString(pzErrMsg, sqlite3_error_string(p->rc), (char*)0);
    sqlite3Error(p->db, p->rc, 0);
  }else{
    sqlite3Error(p->db, SQLITE_OK, 0);
  }
  Cleanup(p);


  /* Figure out which function to call on the btree backends that
  ** have active transactions.

  */
  checkActiveVdbeCnt(db);
  if( db->autoCommit && db->activeVdbeCnt==1 ){
    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
      xFunc = sqlite3BtreeCommit;
      needXcommit = 1;
    }else{
      xFunc = sqlite3BtreeRollback;
    }
  }else{
    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
      xFunc = sqlite3BtreeCommitStmt;
    }else if( p->errorAction==OE_Abort ){
      xFunc = sqlite3BtreeRollbackStmt;
    }else{
      xFunc = sqlite3BtreeRollback;
      db->autoCommit = 1;
    }
  }



  for(i=0; xFunc && i<db->nDb; i++){
    Btree *pBt = db->aDb[i].pBt;
    if( sqlite3BtreeIsInTrans(pBt) ){
      int rc;
      if( db->xCommitCallback && needXcommit ){
        if( db->xCommitCallback(db->pCommitArg)!=0 ){
          p->rc = SQLITE_CONSTRAINT;
          sqlite3Error(db, SQLITE_CONSTRAINT, 0);
          xFunc = sqlite3BtreeRollback;
        }





        needXcommit = 0;
      }





      rc = xFunc(pBt);
      if( p->rc==SQLITE_OK ) p->rc = rc;
    }

  }


  if( p->rc!=SQLITE_OK ){
    sqlite3RollbackInternalChanges(db);
  }





  if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
    db->activeVdbeCnt--;
  }

  assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
#ifdef VDBE_PROFILE
  {
    FILE *out = fopen("vdbe_profile.out", "a");
    if( out ){
      int i;
      fprintf(out, "---- ");
      for(i=0; i<p->nOp; i++){

Changes to test/attach.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
343
344
345
346
347
348
349

350
351
352
353
354
355
356
...
360
361
362
363
364
365
366





367
368
369
370
371
372
373
...
434
435
436
437
438
439
440

441
442
443
444
445

446
447
448
449
450
451
452
#    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: attach.test,v 1.18 2004/05/29 10:23:20 danielk1977 Exp $
#

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

for {set i 2} {$i<=15} {incr i} {
  file delete -force test$i.db
................................................................................
do_test attach-3.7 {
  execsql ROLLBACK
  execsql {SELECT * FROM t2} db2
} {21 x 22 y}
do_test attach-3.8 {
  execsql BEGIN
  execsql BEGIN db2

  catchsql {SELECT * FROM t2}
} {1 {database is locked}}
do_test attach-3.9 {
  catchsql {SELECT * FROM t2} db2
} {0 {21 x 22 y}}
do_test attach-3.10 {
  execsql {SELECT * FROM t1}
................................................................................
} {0 {}}
do_test attach-3.12 {
  execsql {SELECT * FROM t1}
} {2 2 4 4}
do_test attach-3.13 {
  catchsql {UPDATE t2 SET x=x+1 WHERE x=50}
} {1 {database is locked}}





do_test attach-3.14 {
  # Unable to reinitialize the schema tables because the aux database
  # is still locked.
  catchsql {SELECT * FROM t1}
} {1 {database is locked}}
do_test attach-3.15 {
  execsql COMMIT db2
................................................................................
    SELECT * FROM main.t4;
  }
} {main.11}
do_test attach-4.8 {
  execsql {
    ATTACH DATABASE 'test2.db' AS db2;
    INSERT INTO db2.t3 VALUES(13,14);

    SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
  }
} {db2.6 db2.13 main.11}
do_test attach-4.9 {
  execsql {

    INSERT INTO main.t3 VALUES(15,16);
    SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
  }
} {db2.6 db2.13 main.11 main.15}
do_test attach-4.10 {
  execsql {
    DETACH DATABASE db2;







|







 







>







 







>
>
>
>
>







 







>





>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
#    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: attach.test,v 1.19 2004/05/31 08:26:49 danielk1977 Exp $
#

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

for {set i 2} {$i<=15} {incr i} {
  file delete -force test$i.db
................................................................................
do_test attach-3.7 {
  execsql ROLLBACK
  execsql {SELECT * FROM t2} db2
} {21 x 22 y}
do_test attach-3.8 {
  execsql BEGIN
  execsql BEGIN db2
  execsql {UPDATE t2 SET x=0 WHERE 0} db2
  catchsql {SELECT * FROM t2}
} {1 {database is locked}}
do_test attach-3.9 {
  catchsql {SELECT * FROM t2} db2
} {0 {21 x 22 y}}
do_test attach-3.10 {
  execsql {SELECT * FROM t1}
................................................................................
} {0 {}}
do_test attach-3.12 {
  execsql {SELECT * FROM t1}
} {2 2 4 4}
do_test attach-3.13 {
  catchsql {UPDATE t2 SET x=x+1 WHERE x=50}
} {1 {database is locked}}

# Change for version 3. Transaction is no longer rolled back
# for a locked database.
execsql {ROLLBACK}

do_test attach-3.14 {
  # Unable to reinitialize the schema tables because the aux database
  # is still locked.
  catchsql {SELECT * FROM t1}
} {1 {database is locked}}
do_test attach-3.15 {
  execsql COMMIT db2
................................................................................
    SELECT * FROM main.t4;
  }
} {main.11}
do_test attach-4.8 {
  execsql {
    ATTACH DATABASE 'test2.db' AS db2;
    INSERT INTO db2.t3 VALUES(13,14);
pragma vdbe_trace = on;
    SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
  }
} {db2.6 db2.13 main.11}
do_test attach-4.9 {
  execsql {
pragma vdbe_trace = off;
    INSERT INTO main.t3 VALUES(15,16);
    SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
  }
} {db2.6 db2.13 main.11 main.15}
do_test attach-4.10 {
  execsql {
    DETACH DATABASE db2;

Changes to test/attach2.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
47
48
49
50
51
52
53

54
55
56
57
58
59
60
..
73
74
75
76
77
78
79

80
81
82
83
84
85
86
...
104
105
106
107
108
109
110




111
112
113
114
115
116
117
#    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.9 2004/05/21 10:08:55 danielk1977 Exp $
#


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

# Ticket #354
................................................................................
  }
  return $list
}
db eval {DETACH t2}
do_test attach2-2.1 {
  # lock test2.db then try to attach it.  Should get an error.
  db2 eval {BEGIN}

  catchsql {
    ATTACH 'test2.db' AS t2;
  }
} {1 {database is locked}}
do_test attach2-2.2 {
  # make sure test2.db did not get attached.
  db_list db
................................................................................
  catchsql {
    SELECT name FROM t2.sqlite_master;
  }
} {0 {t1 x1}}
do_test attach2-2.6 {
  # lock test2.db and try to read from it.  should get an error.
  db2 eval BEGIN

  catchsql {
    SELECT name FROM t2.sqlite_master;
  }
} {1 {database is locked}}
do_test attach2-2.7 {
  # but we can still read from test1.db even though test2.db is locked.
  catchsql {
................................................................................
  catchsql {
    INSERT INTO t2.t1 VALUES(1,2);
  }
} {1 {database is locked}}
do_test attach2-2.11 {
  # when the write failed in the previous test, the transaction should
  # have rolled back.




  db2 eval ROLLBACK
  execsql {
    SELECT * FROM t1
  }
} {}
do_test attach2-2.12 {
  catchsql {







|







 







>







 







>







 







>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#    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.10 2004/05/31 08:26:49 danielk1977 Exp $
#


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

# Ticket #354
................................................................................
  }
  return $list
}
db eval {DETACH t2}
do_test attach2-2.1 {
  # lock test2.db then try to attach it.  Should get an error.
  db2 eval {BEGIN}
  db2 eval {UPDATE t1 SET a = 0 WHERE 0}
  catchsql {
    ATTACH 'test2.db' AS t2;
  }
} {1 {database is locked}}
do_test attach2-2.2 {
  # make sure test2.db did not get attached.
  db_list db
................................................................................
  catchsql {
    SELECT name FROM t2.sqlite_master;
  }
} {0 {t1 x1}}
do_test attach2-2.6 {
  # lock test2.db and try to read from it.  should get an error.
  db2 eval BEGIN
  db2 eval {UPDATE t1 SET a = 0 WHERE 0}
  catchsql {
    SELECT name FROM t2.sqlite_master;
  }
} {1 {database is locked}}
do_test attach2-2.7 {
  # but we can still read from test1.db even though test2.db is locked.
  catchsql {
................................................................................
  catchsql {
    INSERT INTO t2.t1 VALUES(1,2);
  }
} {1 {database is locked}}
do_test attach2-2.11 {
  # when the write failed in the previous test, the transaction should
  # have rolled back.
  # 
  # Update for version 3: A transaction is no longer rolled back if a
  #                       database is found to be busy.
  execsql {rollback}
  db2 eval ROLLBACK
  execsql {
    SELECT * FROM t1
  }
} {}
do_test attach2-2.12 {
  catchsql {

Changes to test/conflict.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
53
54
55
56
57
58
59


60
61
62
63
64
65
66
..
68
69
70
71
72
73
74


75
76
77
78
79
80
81
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the conflict resolution extension
# to SQLite.
#
# $Id: conflict.test,v 1.19 2003/08/05 13:13:39 drh Exp $

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

# Create tables for the first group of tests.
#
do_test conflict-1.0 {
................................................................................
 13 IGNORE   {INSERT OR ABORT}       1 {}  1
 14 IGNORE   {INSERT OR ROLLBACK}    1 {}  {}
 15 REPLACE  INSERT                  0 4   1
 16 FAIL     INSERT                  1 {}  1
 17 ABORT    INSERT                  1 {}  1
 18 ROLLBACK INSERT                  1 {}  {}
} {


  do_test conflict-1.$i {
    if {$conf!=""} {set conf "ON CONFLICT $conf"}
    set r0 [catch {execsql [subst {
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
................................................................................
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    catch {execsql {COMMIT}}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]


}

# Create tables for the first group of tests.
#
do_test conflict-2.0 {
  execsql {
    DROP TABLE t1;







|







 







>
>







 







>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the conflict resolution extension
# to SQLite.
#
# $Id: conflict.test,v 1.20 2004/05/31 08:26:49 danielk1977 Exp $

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

# Create tables for the first group of tests.
#
do_test conflict-1.0 {
................................................................................
 13 IGNORE   {INSERT OR ABORT}       1 {}  1
 14 IGNORE   {INSERT OR ROLLBACK}    1 {}  {}
 15 REPLACE  INSERT                  0 4   1
 16 FAIL     INSERT                  1 {}  1
 17 ABORT    INSERT                  1 {}  1
 18 ROLLBACK INSERT                  1 {}  {}
} {
  if { $conf=={} } {

  do_test conflict-1.$i {
    if {$conf!=""} {set conf "ON CONFLICT $conf"}
    set r0 [catch {execsql [subst {
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
................................................................................
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    catch {execsql {COMMIT}}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]

  }
}

# Create tables for the first group of tests.
#
do_test conflict-2.0 {
  execsql {
    DROP TABLE t1;

Changes to test/hook.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# The focus of the tests in this file is the  following interface:
#
#      sqlite_commit_hook
#
# $Id: hook.test,v 1.3 2004/01/15 02:44:03 drh Exp $

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

do_test hook-1.2 {
  db commit_hook
} {}
................................................................................
    INSERT INTO t2 VALUES(5,6);
  }
  set commit_cnt
} {1 2 2 3 3 4 4 5 5 6}
do_test hook-3.6 {
  set commit_cnt {}
  proc commit_hook {} {
    set ::commit_cnt [execsql {SELECT * FROM t2}]
    return 1
  }
  catchsql {
    INSERT INTO t2 VALUES(6,7);
  }
} {1 {constraint failed}}
do_test hook-3.7 {
  set commit_cnt
} {1 2 2 3 3 4 4 5 5 6 6 7}
do_test hook-3.8 {
  execsql {SELECT * FROM t2}
} {1 2 2 3 3 4 4 5 5 6}


finish_test







|







 







|







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# The focus of the tests in this file is the  following interface:
#
#      sqlite_commit_hook
#
# $Id: hook.test,v 1.4 2004/05/31 08:26:49 danielk1977 Exp $

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

do_test hook-1.2 {
  db commit_hook
} {}
................................................................................
    INSERT INTO t2 VALUES(5,6);
  }
  set commit_cnt
} {1 2 2 3 3 4 4 5 5 6}
do_test hook-3.6 {
  set commit_cnt {}
  proc commit_hook {} {
    set ::commit_cnt [execsql {SELECT * FROM t2}] 
    return 1
  }
  catchsql {
    INSERT INTO t2 VALUES(6,7);
  }
} {1 {constraint failed}}
do_test hook-3.7 {
  set ::commit_cnt
} {1 2 2 3 3 4 4 5 5 6 6 7}
do_test hook-3.8 {
  execsql {SELECT * FROM t2}
} {1 2 2 3 3 4 4 5 5 6}


finish_test

Changes to test/lock.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
56
57
58
59
60
61
62

63
64
65
66
67
68
69
...
151
152
153
154
155
156
157

158


159
160
161
162
163
164
165
...
218
219
220
221
222
223
224

225
226
227
228
229
230
231
232
233

234
235
236
237
238
239
240
241
242
243

244

245
246
247
248
249
250
251
...
263
264
265
266
267
268
269

270
271
272
273
274
275
276
#    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.  The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.20 2004/02/14 16:31:04 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
  execsql {SELECT * FROM t1} db2
} {2 1}
do_test lock-1.9 {
  execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.10 {
  execsql {BEGIN TRANSACTION}

  execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.11 {
  catchsql {SELECT * FROM t1} db2
} {1 {database is locked}}
do_test lock-1.12 {
  execsql {ROLLBACK}
................................................................................
integrity_check lock-1.23

# If one thread has a transaction another thread cannot start
# a transaction.
#
do_test lock-2.1 {
  execsql {BEGIN TRANSACTION}

  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]


  lappend r $msg
} {1 {database is locked}}

# Nor can the other thread do a query.
#
do_test lock-2.2 {
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
................................................................................
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {9 8} {1 2 3}}
do_test lock-2.7 {
  execsql {BEGIN TRANSACTION}

  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]

  execsql {ROLLBACK} db2
  lappend r $msg
  lappend r $::callback_value
} {0 {} {1 2 3}}

# Test the built-in busy timeout handler
#
do_test lock-2.8 {
  db2 timeout 400
  execsql BEGIN

  catchsql BEGIN db2

} {1 {database is locked}}
do_test lock-2.9 {
  db2 timeout 0
  execsql COMMIT
} {}
integrity_check lock-2.10

................................................................................
# opening a new pointer to the database while another pointer
# has the database locked.
#
do_test lock-4.1 {
  db2 close
  catch {db eval ROLLBACK}
  db eval BEGIN

  sqlite db2 ./test.db
  set rc [catch {db2 eval {SELECT * FROM t1}} msg]
  lappend rc $msg
} {1 {database is locked}}
do_test lock-4.2 {
  set ::callback_value {}
  set rc [catch {db2 eval {SELECT * FROM t1}} msg]







|







 







>







 







>
|
>
>







 







>








|
>










>

>







 







>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#    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.  The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.21 2004/05/31 08:26:49 danielk1977 Exp $


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

# Create an alternative connection to the database
#
................................................................................
  execsql {SELECT * FROM t1} db2
} {2 1}
do_test lock-1.9 {
  execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.10 {
  execsql {BEGIN TRANSACTION}
  execsql {UPDATE t1 SET a = 0 WHERE 0}
  execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.11 {
  catchsql {SELECT * FROM t1} db2
} {1 {database is locked}}
do_test lock-1.12 {
  execsql {ROLLBACK}
................................................................................
integrity_check lock-1.23

# If one thread has a transaction another thread cannot start
# a transaction.
#
do_test lock-2.1 {
  execsql {BEGIN TRANSACTION}
  execsql {UPDATE t1 SET a = 0 WHERE 0}
  execsql {BEGIN TRANSACTION} db2
  set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg]
  execsql {ROLLBACK} db2
  lappend r $msg
} {1 {database is locked}}

# Nor can the other thread do a query.
#
do_test lock-2.2 {
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
................................................................................
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {9 8} {1 2 3}}
do_test lock-2.7 {
  execsql {BEGIN TRANSACTION}
  execsql {UPDATE t1 SET a = 0 WHERE 0}
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback
  execsql {BEGIN TRANSACTION} db2
  set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg]
  execsql {ROLLBACK} db2
  lappend r $msg
  lappend r $::callback_value
} {0 {} {1 2 3}}

# Test the built-in busy timeout handler
#
do_test lock-2.8 {
  db2 timeout 400
  execsql BEGIN
  execsql {UPDATE t1 SET a = 0 WHERE 0}
  catchsql BEGIN db2
  catchsql {UPDATE t1 SET a = 0 WHERE 0} db2
} {1 {database is locked}}
do_test lock-2.9 {
  db2 timeout 0
  execsql COMMIT
} {}
integrity_check lock-2.10

................................................................................
# opening a new pointer to the database while another pointer
# has the database locked.
#
do_test lock-4.1 {
  db2 close
  catch {db eval ROLLBACK}
  db eval BEGIN
  db eval {UPDATE t1 SET a=0 WHERE 0}
  sqlite db2 ./test.db
  set rc [catch {db2 eval {SELECT * FROM t1}} msg]
  lappend rc $msg
} {1 {database is locked}}
do_test lock-4.2 {
  set ::callback_value {}
  set rc [catch {db2 eval {SELECT * FROM t1}} msg]

Changes to test/misc1.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
308
309
310
311
312
313
314

315
316
317
318
319
320
321
...
450
451
452
453
454
455
456

457
458
459
460
461
462
463
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc1.test,v 1.24 2004/05/19 20:41:04 drh Exp $

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

# Test the creation and use of tables that have a large number
# of columns.
#
................................................................................
} {102}

# Make sure the initialization works even if a database is opened while
# another process has the database locked.
#
do_test misc1-11.1 {
  execsql {BEGIN}

  sqlite db2 test.db
  set rc [catch {db2 eval {SELECT count(*) FROM t1}} msg]
  lappend rc $msg
} {1 {database is locked}}
do_test misc1-11.2 {
  execsql {COMMIT}
  set rc [catch {db2 eval {SELECT count(*) FROM t1}} msg]
................................................................................
do_test misc1-14.1 {
  file mkdir tempdir
  cd tempdir
  execsql {BEGIN}
  file exists ./test.db-journal
} {0}
do_test misc1-14.2 {

  file exists ../test.db-journal
} {1}
do_test misc1-14.3 {
  cd ..
  file delete tempdir
  execsql {COMMIT}
  file exists ./test.db-journal







|







 







>







 







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc1.test,v 1.25 2004/05/31 08:26:49 danielk1977 Exp $

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

# Test the creation and use of tables that have a large number
# of columns.
#
................................................................................
} {102}

# Make sure the initialization works even if a database is opened while
# another process has the database locked.
#
do_test misc1-11.1 {
  execsql {BEGIN}
  execsql {UPDATE t1 SET a=0 WHERE 0}
  sqlite db2 test.db
  set rc [catch {db2 eval {SELECT count(*) FROM t1}} msg]
  lappend rc $msg
} {1 {database is locked}}
do_test misc1-11.2 {
  execsql {COMMIT}
  set rc [catch {db2 eval {SELECT count(*) FROM t1}} msg]
................................................................................
do_test misc1-14.1 {
  file mkdir tempdir
  cd tempdir
  execsql {BEGIN}
  file exists ./test.db-journal
} {0}
do_test misc1-14.2 {
  execsql {UPDATE t1 SET a=0 WHERE 0}
  file exists ../test.db-journal
} {1}
do_test misc1-14.3 {
  cd ..
  file delete tempdir
  execsql {COMMIT}
  file exists ./test.db-journal

Changes to test/progress.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
..
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#    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.  The
# focus of this file is testing the 'progress callback'.
#
# $Id: progress.test,v 1.1 2003/10/18 09:37:27 danielk1977 Exp $

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

# Build some test data
#
execsql {
................................................................................
  expr $counter > 1
} 1

# Test that the query is abandoned when the progress callback returns non-zero
do_test progress1.1 {
  set counter 0
  db progress 1 "[namespace code {incr counter}] ; expr 1"
  execsql {
    SELECT * FROM t1
  }
  set counter 
} 1

# Test that the query is rolled back when the progress callback returns
# non-zero.
do_test progress1.2 {

  # This figures out how many opcodes it takes to copy 5 extra rows into t1.
  db progress 1 "[namespace code {incr five_rows}] ; expr 0"
................................................................................
  }

  # Now set up the progress callback to abandon the query after the number of
  # opcodes to copy 5 rows. That way, when we try to copy 6 rows, we know
  # some data will have been inserted into the table by the time the progress
  # callback abandons the query.
  db progress $five_rows "expr 1"
  execsql {
    INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 7
  }
  execsql {
    SELECT count(*) FROM t1
  }
} 10

# Test that an active transaction remains active and not rolled back after the
................................................................................

  db progress 0 ""
  execsql BEGIN
  execsql {
    INSERT INTO t1 VALUES(11)
  }
  db progress 1 "expr 1"
  execsql {
    INSERT INTO t1 VALUES(12)
  }
  db progress 0 ""
  execsql COMMIT
  execsql {
    SELECT count(*) FROM t1
  }







|







 







|

|
|
|







 







|
|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
..
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#    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.  The
# focus of this file is testing the 'progress callback'.
#
# $Id: progress.test,v 1.2 2004/05/31 08:26:50 danielk1977 Exp $

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

# Build some test data
#
execsql {
................................................................................
  expr $counter > 1
} 1

# Test that the query is abandoned when the progress callback returns non-zero
do_test progress1.1 {
  set counter 0
  db progress 1 "[namespace code {incr counter}] ; expr 1"
  set rc [catch {execsql {
    SELECT * FROM t1
  }}]
  list $counter $rc
} {1 1}

# Test that the query is rolled back when the progress callback returns
# non-zero.
do_test progress1.2 {

  # This figures out how many opcodes it takes to copy 5 extra rows into t1.
  db progress 1 "[namespace code {incr five_rows}] ; expr 0"
................................................................................
  }

  # Now set up the progress callback to abandon the query after the number of
  # opcodes to copy 5 rows. That way, when we try to copy 6 rows, we know
  # some data will have been inserted into the table by the time the progress
  # callback abandons the query.
  db progress $five_rows "expr 1"
  catchsql {
    INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 9
  }
  execsql {
    SELECT count(*) FROM t1
  }
} 10

# Test that an active transaction remains active and not rolled back after the
................................................................................

  db progress 0 ""
  execsql BEGIN
  execsql {
    INSERT INTO t1 VALUES(11)
  }
  db progress 1 "expr 1"
  catchsql {
    INSERT INTO t1 VALUES(12)
  }
  db progress 0 ""
  execsql COMMIT
  execsql {
    SELECT count(*) FROM t1
  }

Changes to test/trans.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
84
85
86
87
88
89
90

91
92
93
94
95
96
97
...
179
180
181
182
183
184
185

186
187
188
189
190
191
192
#    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.  The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.19 2004/03/08 13:26:18 drh Exp $


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


# Create several tables to work with.
................................................................................
integrity_check trans-2.11

# Check the locking behavior
#
do_test trans-3.1 {
  execsql {
    BEGIN;

    SELECT a FROM one ORDER BY a;
  }
} {1 2 3}
do_test trans-3.2 {
  set v [catch {execsql {
    SELECT a FROM two ORDER BY a;
  } altdb} msg]
................................................................................
    ROLLBACK;
  } db} msg]
  lappend v $msg
} {1 {cannot rollback - no transaction is active}}
do_test trans-4.3 {
  set v [catch {execsql {
    BEGIN TRANSACTION;

    SELECT a FROM two ORDER BY a;
  } db} msg]
  lappend v $msg
} {0 {1 4 5 10}}
do_test trans-4.4 {
  set v [catch {execsql {
    SELECT a FROM two ORDER BY a;







|







 







>







 







>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#    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.  The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.20 2004/05/31 08:26:50 danielk1977 Exp $


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


# Create several tables to work with.
................................................................................
integrity_check trans-2.11

# Check the locking behavior
#
do_test trans-3.1 {
  execsql {
    BEGIN;
    UPDATE one SET a = 0 WHERE 0;
    SELECT a FROM one ORDER BY a;
  }
} {1 2 3}
do_test trans-3.2 {
  set v [catch {execsql {
    SELECT a FROM two ORDER BY a;
  } altdb} msg]
................................................................................
    ROLLBACK;
  } db} msg]
  lappend v $msg
} {1 {cannot rollback - no transaction is active}}
do_test trans-4.3 {
  set v [catch {execsql {
    BEGIN TRANSACTION;
    UPDATE two SET a = 0 WHERE 0;
    SELECT a FROM two ORDER BY a;
  } db} msg]
  lappend v $msg
} {0 {1 4 5 10}}
do_test trans-4.4 {
  set v [catch {execsql {
    SELECT a FROM two ORDER BY a;