/ Check-in [bd7d6a64]
Login

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

Overview
Comment:Additional test cases with locking fixes. Also, make the code thread-safe. (CVS 262)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:bd7d6a64afa03cc64f6537f828d6c94975bf5f02
User & Date: drh 2001-09-23 19:46:52
Context
2001-09-23
20:17
RowIDs are now always expressed in native byte order. (CVS 263) check-in: bb4313a9 user: drh tags: trunk
19:46
Additional test cases with locking fixes. Also, make the code thread-safe. (CVS 262) check-in: bd7d6a64 user: drh tags: trunk
02:35
Fixes to the locking and rollback behavior. (CVS 261) check-in: 337b3d3b user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.39 2001/09/23 02:35:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
................................................................................
** 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.
*/
static void changeCookie(sqlite *db){
  if( db->next_cookie==db->schema_cookie ){
    db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
    db->flags |= SQLITE_InternChanges;
  }
}

/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.







|







 







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.40 2001/09/23 19:46:52 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
................................................................................
** 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.
*/
static void changeCookie(sqlite *db){
  if( db->next_cookie==db->schema_cookie ){
    db->next_cookie = db->schema_cookie + sqliteRandomByte(db) + 1;
    db->flags |= SQLITE_InternChanges;
  }
}

/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.

Changes to src/os.c.

242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
425
426
427
428
429
430
431

432
433
434
435
436
437
438
439
440
441
442
443
444







445
446
447
448
449
450
451
    zDir = azDirs[i];
    break;
  }
  do{
    sprintf(zBuf, "%s/sqlite_", zDir);
    j = strlen(zBuf);
    for(i=0; i<15; i++){
      int n = sqliteRandomByte() % sizeof(zChars);
      zBuf[j++] = zChars[n];
    }
    zBuf[j] = 0;
  }while( access(zBuf,0)==0 );
#endif
#if OS_WIN
  static char zChars[] =
................................................................................
  int i, j;
  char zTempPath[SQLITE_TEMPNAME_SIZE];
  GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath);
  for(;;){
    sprintf(zBuf, "%s/sqlite_", zTempPath);
    j = strlen(zBuf);
    for(i=0; i<15; i++){
      int n = sqliteRandomByte() % sizeof(zChars);
      zBuf[j++] = zChars[n];
    }
    zBuf[j] = 0;
    if( !sqliteOsFileExists(zBuf) ) break;
  }
#endif
  return SQLITE_OK; 
................................................................................
#endif
}

/*
** Get information to seed the random number generator.
*/
int sqliteOsRandomSeed(char *zBuf){

#if OS_UNIX
  int pid;
  time((time_t*)zBuf);
  zBuf += sizeof(time_t);
  pid = getpid();
  memcpy(zBuf, &pid, sizeof(pid));
  zBuf += pid;
  return SQLITE_OK;
#endif
#if OS_WIN
  GetSystemTime((LPSYSTEMTIME)zBuf);
  return SQLITE_OK;
#endif 







}

/*
** Sleep for a little while.  Return the amount of time slept.
*/
int sqliteOsSleep(int ms){
#if OS_UNIX







|







 







|







 







>



<

|
<
<



<
|
>
>
>
>
>
>
>







242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
425
426
427
428
429
430
431
432
433
434
435

436
437


438
439
440

441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
    zDir = azDirs[i];
    break;
  }
  do{
    sprintf(zBuf, "%s/sqlite_", zDir);
    j = strlen(zBuf);
    for(i=0; i<15; i++){
      int n = rand() % sizeof(zChars);
      zBuf[j++] = zChars[n];
    }
    zBuf[j] = 0;
  }while( access(zBuf,0)==0 );
#endif
#if OS_WIN
  static char zChars[] =
................................................................................
  int i, j;
  char zTempPath[SQLITE_TEMPNAME_SIZE];
  GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath);
  for(;;){
    sprintf(zBuf, "%s/sqlite_", zTempPath);
    j = strlen(zBuf);
    for(i=0; i<15; i++){
      int n = rand() % sizeof(zChars);
      zBuf[j++] = zChars[n];
    }
    zBuf[j] = 0;
    if( !sqliteOsFileExists(zBuf) ) break;
  }
#endif
  return SQLITE_OK; 
................................................................................
#endif
}

/*
** Get information to seed the random number generator.
*/
int sqliteOsRandomSeed(char *zBuf){
  static int once = 1;
#if OS_UNIX
  int pid;
  time((time_t*)zBuf);

  pid = getpid();
  memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));


#endif
#if OS_WIN
  GetSystemTime((LPSYSTEMTIME)zBuf);

#endif
  if( once ){
    int seed;
    memcpy(&seed, zBuf, sizeof(seed));
    srand(seed);
    once = 0;
  }
  return SQLITE_OK;
}

/*
** Sleep for a little while.  Return the amount of time slept.
*/
int sqliteOsSleep(int ms){
#if OS_UNIX

Changes to src/random.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
*************************************************************************
** This file contains code to implement a pseudo-random number
** generator (PRNG) for SQLite.
**
** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames.
**
** $Id: random.c,v 1.6 2001/09/19 13:22:40 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** Get a single 8-bit random value from the RC4 PRNG.
*/
int sqliteRandomByte(void){
  int t;

  /*
  ** The following structure holds the current state of the RC4 algorithm.
  ** We use RC4 as a random number generator.  Each call to RC4 gives
  ** a random 8-bit number.
  **
  ** Nothing in this file or anywhere else in SQLite does any kind of
  ** encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
  ** number generator) not as an encryption device.
  */
  static struct {
    int isInit;
    int i, j;
    int s[256];
  } prng_state;
 
  /* Initialize the state of the random number generator once,
  ** the first time this routine is called.  The seed value does
  ** not need to contain a lot of randomness since we are not
  ** trying to do secure encryption or anything like that...
  */
  if( !prng_state.isInit ){
    int i;
    static char seed[] = "    sqlite random seed abcdefghijklmnop";
    char k[256];
    sqliteOsRandomSeed(seed);
    prng_state.j = 0;
    prng_state.i = 0;

    for(i=0; i<256; i++){
      prng_state.s[i] = i;
      k[i] = seed[i%sizeof(seed)];
    }
    for(i=0; i<256; i++){
      int t;
      prng_state.j = (prng_state.j + prng_state.s[i] + k[i]) & 0xff;
      t = prng_state.s[prng_state.j];
      prng_state.s[prng_state.j] = prng_state.s[i];
      prng_state.s[i] = t;
    }
    prng_state.isInit = 1;
  }

  /* Generate and return single random byte
  */
  prng_state.i = (prng_state.i + 1) & 0xff;
  prng_state.j = (prng_state.j + prng_state.s[prng_state.i]) & 0xff;
  t = prng_state.s[prng_state.i];
  prng_state.s[prng_state.i] = prng_state.s[prng_state.j];
  prng_state.s[prng_state.j] = t;
  t = prng_state.s[prng_state.i] + prng_state.s[prng_state.j];
  return prng_state.s[t & 0xff];
}

/*
** Return a random 32-bit integer.  The integer is generated by making
** 4 calls to sqliteRandomByte().
*/
int sqliteRandomInteger(void){
  int r;
  int i;
  r = sqliteRandomByte();
  for(i=1; i<4; i++){
    r = (r<<8) + sqliteRandomByte();
  }
  return r;
}

/*
** Return a random 16-bit unsigned integer.  The integer is generated by
** making 2 calls to sqliteRandomByte().
*/
int sqliteRandomShort(void){
  int r;
  r = sqliteRandomByte();
  r = (r<<8) + sqliteRandomByte();
  return r;
}

/*
** Generate a random filename with the given prefix.  The new filename
** is written into zBuf[].  The calling function must insure that
** zBuf[] is big enough to hold the prefix plus 20 or so extra
** characters.
**
** Very random names are chosen so that the chance of a
** collision with an existing filename is very very small.
*/
void sqliteRandomName(char *zBuf, char *zPrefix){
  int i, j;
  static const char zRandomChars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  strcpy(zBuf, zPrefix);
  j = strlen(zBuf);
  for(i=0; i<15; i++){
    int c = sqliteRandomByte() % (sizeof(zRandomChars) - 1);
    zBuf[j++] = zRandomChars[c];
  }
  zBuf[j] = 0;
}







|







|
|
|
|
|
|
|





<
<
<
<
<
<
<
<
<
<
<
|

<

<
|
|
>

|
<



|
|
|
|

|




|
|
|
|
|
|
|






|


|

|



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37











38
39

40

41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
































*************************************************************************
** This file contains code to implement a pseudo-random number
** generator (PRNG) for SQLite.
**
** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames.
**
** $Id: random.c,v 1.7 2001/09/23 19:46:52 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** Get a single 8-bit random value from the RC4 PRNG.
*/
int sqliteRandomByte(sqlite *db){
  int t;

  /* Initialize the state of the random number generator once,
  ** the first time this routine is called.  The seed value does
  ** not need to contain a lot of randomness since we are not
  ** trying to do secure encryption or anything like that...
  **
  ** Nothing in this file or anywhere else in SQLite does any kind of
  ** encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
  ** number generator) not as an encryption device.
  */











  if( !db->prng.isInit ){
    int i;

    char k[256];

    db->prng.j = 0;
    db->prng.i = 0;
    sqliteOsRandomSeed(k);
    for(i=0; i<256; i++){
      db->prng.s[i] = i;

    }
    for(i=0; i<256; i++){
      int t;
      db->prng.j = (db->prng.j + db->prng.s[i] + k[i]) & 0xff;
      t = db->prng.s[db->prng.j];
      db->prng.s[db->prng.j] = db->prng.s[i];
      db->prng.s[i] = t;
    }
    db->prng.isInit = 1;
  }

  /* Generate and return single random byte
  */
  db->prng.i = (db->prng.i + 1) & 0xff;
  db->prng.j = (db->prng.j + db->prng.s[db->prng.i]) & 0xff;
  t = db->prng.s[db->prng.i];
  db->prng.s[db->prng.i] = db->prng.s[db->prng.j];
  db->prng.s[db->prng.j] = t;
  t = db->prng.s[db->prng.i] + db->prng.s[db->prng.j];
  return db->prng.s[t & 0xff];
}

/*
** Return a random 32-bit integer.  The integer is generated by making
** 4 calls to sqliteRandomByte().
*/
int sqliteRandomInteger(sqlite *db){
  int r;
  int i;
  r = sqliteRandomByte(db);
  for(i=1; i<4; i++){
    r = (r<<8) + sqliteRandomByte(db);
  }
  return r;
}
































Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
144
145
146
147
148
149
150






151
152
153
154
155
156
157
...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
**    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.53 2001/09/22 18:12:10 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
  int schema_cookie;            /* Magic number that changes with the schema */
  int next_cookie;              /* Value of schema_cookie after commit */
  int nTable;                   /* Number of tables in the database */
  void *pBusyArg;               /* 1st Argument to the busy callback */
  int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
  Hash tblHash;                 /* All tables indexed by name */
  Hash idxHash;                 /* All (named) indices indexed by name */






};

/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_Initialized    0x00000002  /* True after initialization */
................................................................................
int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
void sqliteParseInfoReset(Parse*);
Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void);
int sqliteRandomInteger(void);
void sqliteRandomName(char*,char*);
void sqliteBeginTransaction(Parse*);
void sqliteCommitTransaction(Parse*);
void sqliteRollbackTransaction(Parse*);
char *sqlite_mprintf(const char *, ...);
const char *sqliteErrStr(int);







|







 







>
>
>
>
>
>







 







|
|
<





7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
453
454
455
456
457
458
459
460
461

462
463
464
465
466
**    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.54 2001/09/23 19:46:52 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
  int schema_cookie;            /* Magic number that changes with the schema */
  int next_cookie;              /* Value of schema_cookie after commit */
  int nTable;                   /* Number of tables in the database */
  void *pBusyArg;               /* 1st Argument to the busy callback */
  int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
  Hash tblHash;                 /* All tables indexed by name */
  Hash idxHash;                 /* All (named) indices indexed by name */
  struct {                      /* State of the RC4 random number generator */
    int isInit;                    /* True if initialized */
    int i, j;                      /* State variables */
    int s[256];                    /* State variables */
  } prng;
  int nextRowid;                /* Next generated rowID */
};

/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_Initialized    0x00000002  /* True after initialization */
................................................................................
int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
void sqliteParseInfoReset(Parse*);
Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(sqlite*);
int sqliteRandomInteger(sqlite*);

void sqliteBeginTransaction(Parse*);
void sqliteCommitTransaction(Parse*);
void sqliteRollbackTransaction(Parse*);
char *sqlite_mprintf(const char *, ...);
const char *sqliteErrStr(int);

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1882
1883
1884
1885
1886
1887
1888


1889

















1890
1891
1892
1893
1894
1895
1896
....
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
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.74 2001/09/23 02:35:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
................................................................................
** started.  No other process can read or write the file while the
** 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: {


  rc = sqliteBtreeBeginTrans(pBt);

















  break;
}

/* Opcode: Commit * * *
**
** Cause all modifications to the database that have been made since the
** last Transaction to actually take effect.  No additional modifications
................................................................................
    **
    ** To promote locality of reference for repetitive inserts, the
    ** first few attempts at chosing a rowid pick values just a little
    ** larger than the previous rowid.  This has been shown experimentally
    ** to double the speed of the COPY operation.
    */
    int res, rx, cnt;
    static int x = 0;
    union {
       char zBuf[sizeof(int)];
       int i;
    } ux;
    cnt = 0;

    do{
      if( cnt>5 ){
        x = sqliteRandomInteger();
      }else{
        x += sqliteRandomByte() + 1;
      }
      if( x==0 ) continue;
      ux.zBuf[3] = x&0xff;
      ux.zBuf[2] = (x>>8)&0xff;
      ux.zBuf[1] = (x>>16)&0xff;
      ux.zBuf[0] = (x>>24)&0xff;
      v = ux.i;
      rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, &v, sizeof(v), &res);
      cnt++;
    }while( cnt<1000 && rx==SQLITE_OK && res==0 );

    if( rx==SQLITE_OK && res==0 ){
      rc = SQLITE_FULL;
      goto abort_due_to_error;
    }
  }
  VERIFY( NeedStack(p, p->tos+1); )
  p->tos++;







|







 







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







 







|





>


|

|










>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
....
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
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.75 2001/09/23 19:46:52 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
................................................................................
** started.  No other process can read or write the file while the
** 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 = 0;
  do{
    rc = sqliteBtreeBeginTrans(pBt);
    switch( rc ){
      case SQLITE_BUSY: {
        if( xBusy==0 || (*xBusy)(pBusyArg, "", ++busy)==0 ){
          sqliteSetString(pzErrMsg, sqliteErrStr(rc), 0);
          busy = 0;
        }
        break;
      }
      case SQLITE_OK: {
        busy = 0;
        break;
      }
      default: {
        goto abort_due_to_error;
      }
    }
  }while( busy );
  break;
}

/* Opcode: Commit * * *
**
** Cause all modifications to the database that have been made since the
** last Transaction to actually take effect.  No additional modifications
................................................................................
    **
    ** To promote locality of reference for repetitive inserts, the
    ** first few attempts at chosing a rowid pick values just a little
    ** larger than the previous rowid.  This has been shown experimentally
    ** to double the speed of the COPY operation.
    */
    int res, rx, cnt;
    int x;
    union {
       char zBuf[sizeof(int)];
       int i;
    } ux;
    cnt = 0;
    x = db->nextRowid;
    do{
      if( cnt>5 ){
        x = sqliteRandomInteger(db);
      }else{
        x += sqliteRandomByte(db) + 1;
      }
      if( x==0 ) continue;
      ux.zBuf[3] = x&0xff;
      ux.zBuf[2] = (x>>8)&0xff;
      ux.zBuf[1] = (x>>16)&0xff;
      ux.zBuf[0] = (x>>24)&0xff;
      v = ux.i;
      rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, &v, sizeof(v), &res);
      cnt++;
    }while( cnt<1000 && rx==SQLITE_OK && res==0 );
    db->nextRowid = x;
    if( rx==SQLITE_OK && res==0 ){
      rc = SQLITE_FULL;
      goto abort_due_to_error;
    }
  }
  VERIFY( NeedStack(p, p->tos+1); )
  p->tos++;

Changes to test/lock.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
147
148
149
150
151
152
153
154


155





























































































156
157
158
159
160
#    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.11 2001/09/23 02:35:53 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
    db eval {SELECT * FROM t1} qv {
      set r [catch {db2 eval {SELECT a FROM t1}} msg]
      lappend r $msg
    }
    set r
  } {0 2}
}

































































































do_test lock-999.1 {
  rename db2 {}
} {}

finish_test







|







 








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





7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#    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.12 2001/09/23 19:46:52 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
    db eval {SELECT * FROM t1} qv {
      set r [catch {db2 eval {SELECT a FROM t1}} msg]
      lappend r $msg
    }
    set r
  } {0 2}
}

# 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]
  lappend r $msg
} {1 {database is locked}}

# If the other thread (the one that does not hold the transaction)
# tries to start a transaction, we get a busy callback.
#
do_test lock-2.3 {
  proc callback {args} {
    set ::callback_value $args
    break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {{} 1}}
do_test lock-2.4 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
do_test lock-2.5 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {1 2 3 4 5}}

# In this test, the 3rd invocation of the busy callback causes
# the first thread to release its transaction.  That allows the
# second thread to continue.
#
do_test lock-2.6 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  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}}

# Try to start two transactions in a row
#
do_test lock-3.1 {
  execsql {BEGIN TRANSACTION}
  set r [catch {execsql {BEGIN TRANSACTION}} msg]
  execsql {ROLLBACK}
  lappend r $msg
} {0 {}}


do_test lock-999.1 {
  rename db2 {}
} {}

finish_test

Changes to www/changes.tcl.

12
13
14
15
16
17
18




19
20
21
22
23
24
25
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}





chng {2001 Sep 20 (2.0-alpha-2)} {
<li>Initial release of version 2.0.  The idea of renaming the library
    to "SQLus" was abandoned in favor of keeping the "SQLite" name and
    bumping the major version number.</li>
<li>The pager and btree subsystems added back. They are now the only
    available backend.</li>







>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}

chng {2001 Sep 22 (2.0-beta-1)} {
<li>Fixes to the rollback and locking behavior</li>
}

chng {2001 Sep 20 (2.0-alpha-2)} {
<li>Initial release of version 2.0.  The idea of renaming the library
    to "SQLus" was abandoned in favor of keeping the "SQLite" name and
    bumping the major version number.</li>
<li>The pager and btree subsystems added back. They are now the only
    available backend.</li>