/ Check-in [484b82d8]
Login

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

Overview
Comment:Fix the locking protocol. (CVS 280)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:484b82d8a1c84f3d9725a509de93276b9fa9b294
User & Date: drh 2001-10-09 04:19:47
Context
2001-10-09
04:21
Version 2.0.2 (CVS 281) check-in: 765359c7 user: drh tags: trunk
04:19
Fix the locking protocol. (CVS 280) check-in: 484b82d8 user: drh tags: trunk
2001-10-08
13:22
Support for temporary tables added. Still need more testing. (CVS 279) check-in: 9368c62e 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
...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.45 2001/10/08 13:22:32 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 
................................................................................

  if( pEnd==0 || pParse->nErr || sqlite_malloc_failed ) return;
  p = pParse->pNewTable;
  if( p==0 ) return;

  /* Add the table to the in-memory representation of the database.
  */
  assert( pParse->nameClash==0 || pParse->initFlag==0 );
  if( pParse->explain==0 && pParse->nameClash==0 ){
    sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
    pParse->pNewTable = 0;
    db->nTable++;
    db->flags |= SQLITE_InternChanges;
  }








|







 







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.46 2001/10/09 04:19:47 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 
................................................................................

  if( pEnd==0 || pParse->nErr || sqlite_malloc_failed ) return;
  p = pParse->pNewTable;
  if( p==0 ) return;

  /* Add the table to the in-memory representation of the database.
  */
  assert( pParse->nameClash==0 || pParse->initFlag==1 );
  if( pParse->explain==0 && pParse->nameClash==0 ){
    sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
    pParse->pNewTable = 0;
    db->nTable++;
    db->flags |= SQLITE_InternChanges;
  }

Changes to src/hash.h.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This is the header file for the generic hash-table implemenation
** used in SQLite.
**
** $Id: hash.h,v 1.1 2001/09/22 18:12:10 drh Exp $
*/
#ifndef _SQLITE_HASH_H_
#define _SQLITE_HASH_H_

/* Forward declarations of structures. */
typedef struct Hash Hash;
typedef struct HashElem HashElem;
................................................................................
** code should not attempt to access or modify the fields of this structure
** directly.  Change this structure only by using the routines below.
** However, many of the "procedures" and "functions" for modifying and
** accessing this structure are really macros, so we can't really make
** this structure opaque.
*/
struct Hash {
  char keyClass;          /* SQLITE_HASH_INT, ..._STRING, or _BINARY */
  char copyKey;           /* True if copy of key made on insert */
  int count;              /* Number of entries in this table */
  HashElem *first;        /* The first element of the array */
  int htsize;             /* Number of buckets in the hash table */
  struct _ht {            /* the hash table */
    int count;               /* Number of entries with this hash */
    HashElem *chain;         /* Pointer to first entry with this hash */







|







 







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This is the header file for the generic hash-table implemenation
** used in SQLite.
**
** $Id: hash.h,v 1.2 2001/10/09 04:19:47 drh Exp $
*/
#ifndef _SQLITE_HASH_H_
#define _SQLITE_HASH_H_

/* Forward declarations of structures. */
typedef struct Hash Hash;
typedef struct HashElem HashElem;
................................................................................
** code should not attempt to access or modify the fields of this structure
** directly.  Change this structure only by using the routines below.
** However, many of the "procedures" and "functions" for modifying and
** accessing this structure are really macros, so we can't really make
** this structure opaque.
*/
struct Hash {
  char keyClass;          /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */
  char copyKey;           /* True if copy of key made on insert */
  int count;              /* Number of entries in this table */
  HashElem *first;        /* The first element of the array */
  int htsize;             /* Number of buckets in the hash table */
  struct _ht {            /* the hash table */
    int count;               /* Number of entries with this hash */
    HashElem *chain;         /* Pointer to first entry with this hash */

Changes to src/os.c.

32
33
34
35
36
37
38



































































39
40
41
42
43
44
45
..
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
...
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
...
188
189
190
191
192
193
194

195
196
197
198







199
200
201
202
203
204
205
206
...
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
...
275
276
277
278
279
280
281
282



283
284
285
286
287
288
289
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
...
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

388
389
390
391
392
393
394





















395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
...
412
413
414
415
416
417
418















419
420
421
422
423
424


425
426
427
428
429
430
431
...
465
466
467
468
469
470
471





















# include <fcntl.h>
# include <sys/stat.h>
# include <time.h>
#endif
#if OS_WIN
# include <winbase.h>
#endif




































































/*
** Delete the named file
*/
int sqliteOsDelete(const char *zFilename){
#if OS_UNIX
  unlink(zFilename);
................................................................................
*/
int sqliteOsOpenReadWrite(
  const char *zFilename,
  OsFile *pResult,
  int *pReadonly
){
#if OS_UNIX

  int fd = open(zFilename, O_RDWR|O_CREAT, 0644);
  if( fd<0 ){
    fd = open(zFilename, O_RDONLY);
    if( fd<0 ){
      return SQLITE_CANTOPEN; 
    }
    *pReadonly = 1;
  }else{
    *pReadonly = 0;
  }







  *pResult = fd;
  return SQLITE_OK;
#endif
#if OS_WIN
  HANDLE h = CreateFile(zFilename,
     GENERIC_READ | GENERIC_WRITE,
     FILE_SHARE_READ | FILE_SHARE_WRITE,
     NULL,
................................................................................
**
** On success, write the file handle into *pResult and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqliteOsOpenExclusive(const char *zFilename, OsFile *pResult){
#if OS_UNIX
  int fd;
  if( access(zFilename, 0)==0 ){
    return SQLITE_CANTOPEN;
  }
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif
  fd = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600);
  if( fd<0 ){
    return SQLITE_CANTOPEN;
  }







  *pResult = fd;
  return SQLITE_OK;
#endif
#if OS_WIN
  HANDLE h = CreateFile(zFilename,
     GENERIC_READ | GENERIC_WRITE,
     0,
     NULL,
................................................................................
**
** On success, write the file handle into *pResult and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqliteOsOpenReadOnly(const char *zFilename, OsFile *pResult){
#if OS_UNIX

  int fd = open(zFilename, O_RDONLY);
  if( fd<0 ){
    return SQLITE_CANTOPEN;
  }







  *pResult = fd;
  return SQLITE_OK;
#endif
#if OS_WIN
  HANDLE h = CreateFile(zFilename,
     GENERIC_READ,
     0,
     NULL,
................................................................................
    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; 
................................................................................
}

/*
** Close a file
*/
int sqliteOsClose(OsFile id){
#if OS_UNIX
  close(id);



  return SQLITE_OK;
#endif
#if OS_WIN
  CloseHandle(id);
  return SQLITE_OK;
#endif
}
................................................................................
/*
** Read data from a file into a buffer.  Return the number of
** bytes actually read.
*/
int sqliteOsRead(OsFile id, void *pBuf, int amt){
#if OS_UNIX
  int got;
  got = read(id, pBuf, amt);
  if( got<0 ) got = 0;
  return got==amt ? SQLITE_OK : SQLITE_IOERR;
#endif
#if OS_WIN
  DWORD got;
  if( !ReadFile(id, pBuf, amt, &got, 0) ){
    got = 0;
................................................................................
/*
** Write data from a buffer into a file.  Return SQLITE_OK on success
** or some other error code on failure.
*/
int sqliteOsWrite(OsFile id, const void *pBuf, int amt){
#if OS_UNIX
  int wrote;
  wrote = write(id, pBuf, amt);
  if( wrote<amt ) return SQLITE_FULL;
  return SQLITE_OK;
#endif
#if OS_WIN
  DWORD wrote;
  if( !WriteFile(id, pBuf, amt, &wrote, 0) || wrote<amt ){
    return SQLITE_FULL;
................................................................................
}

/*
** Move the read/write pointer in a file.
*/
int sqliteOsSeek(OsFile id, int offset){
#if OS_UNIX
  lseek(id, offset, SEEK_SET);
  return SQLITE_OK;
#endif
#if OS_WIN
  SetFilePointer(id, offset, 0, FILE_BEGIN);
  return SQLITE_OK;
#endif
}

/*
** Make sure all writes to a particular file are committed to disk.
*/
int sqliteOsSync(OsFile id){
#if OS_UNIX
  return fsync(id)==0 ? SQLITE_OK : SQLITE_IOERR;
#endif
#if OS_WIN
  return FlushFileBuffers(id) ? SQLITE_OK : SQLITE_IOERR;
#endif
}

/*
** Truncate an open file to a specified size
*/
int sqliteOsTruncate(OsFile id, int nByte){
#if OS_UNIX
  return ftruncate(id, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
#endif
#if OS_WIN
  SetFilePointer(id, nByte, 0, FILE_BEGIN);
  SetEndOfFile(id);
  return SQLITE_OK;
#endif
}
................................................................................

/*
** Determine the current size of a file in bytes
*/
int sqliteOsFileSize(OsFile id, int *pSize){
#if OS_UNIX
  struct stat buf;
  if( fstat(id, &buf)!=0 ){
    return SQLITE_IOERR;
  }
  *pSize = buf.st_size;
  return SQLITE_OK;
#endif
#if OS_WIN
  *pSize = GetFileSize(id, 0);
  return SQLITE_OK;
#endif
}


/*
** Get a read or write lock on a file.
*/
int sqliteOsLock(OsFile id, int wrlock){
#if OS_UNIX
  int rc;





















  struct flock lock;
  lock.l_type = wrlock ? F_WRLCK : F_RDLCK;
  lock.l_whence = SEEK_SET;
  lock.l_start = lock.l_len = 0L;
  rc = fcntl(id, F_SETLK, &lock);
  if( rc ){
    fcntl(id, F_GETLK, &lock);  /* For debugging */
  }
  return rc==0 ? SQLITE_OK : SQLITE_BUSY;
#endif
#if OS_WIN
  if( !LockFile(id, 0, 0, 1024, 0) ){
    return SQLITE_BUSY;
  }
  return SQLITE_OK;
#endif
................................................................................

/*
** Release the read or write lock from a file.
*/
int sqliteOsUnlock(OsFile id){
#if OS_UNIX
  int rc;















  struct flock lock;
  lock.l_type = F_UNLCK;
  lock.l_whence = SEEK_SET;
  lock.l_start = lock.l_len = 0L;
  rc = fcntl(id, F_SETLK, &lock);
  return rc==0 ? SQLITE_OK : SQLITE_IOERR;


#endif
#if OS_WIN
  return UnlockFile(id, 0, 0, 1024, 0) ? SQLITE_OK : SQLITE_IOERR;
#endif
}

/*
................................................................................
#endif
#endif
#if OS_WIN
  Sleep(ms);
  return ms;
#endif
}




























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







 







>
|
|
|
|






>
>
>
>
>
>
>
|







 







|






|
|


>
>
>
>
>
>
>
|







 







>
|
|


>
>
>
>
>
>
>
|







 







|







 







|







 







|
>
>
>







 







|







 







|







 







|













|











|







 







|










>







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

|







 







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







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
...
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
...
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
...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
...
422
423
424
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
456
457
458
459
460
461
462
...
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514


515
516
517
518
519
520
521
522
523
...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550

551
552
553
554
555
556
557
558
559
560
...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
# include <fcntl.h>
# include <sys/stat.h>
# include <time.h>
#endif
#if OS_WIN
# include <winbase.h>
#endif


#if OS_UNIX
/*
** An instance of the following structure serves as the key used
** to locate a particular lockInfo structure given its inode. 
*/
struct inodeKey {
  dev_t dev;   /* Device number */
  ino_t ino;   /* Inode number */
};

/*
** An instance of the following structure is allocated for each inode.
** A single inode can have multiple file descriptors, so each OsFile structure
** contains a pointer to an instance of this object.
*/
struct lockInfo {
  struct inodeKey key;  /* The lookup key */
  int cnt;              /* 0: unlocked.  -1: write lock.  >=1: read lock */
  int nRef;             /* Number of pointers to this structure */
};

/* 
** This hash table maps inodes (in the form of inodeKey structures) into
** pointers to lockInfo structures.
*/
static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };

/*
** Given a file descriptor, locate a lockInfo structure that describes
** that file descriptor.  Create a new one if necessary.
*/
static struct lockInfo *findLockInfo(int fd){
  int rc;
  struct inodeKey key;
  struct stat statbuf;
  struct lockInfo *pInfo;
  rc = fstat(fd, &statbuf);
  if( rc!=0 ) return 0;
  key.dev = statbuf.st_dev;
  key.ino = statbuf.st_ino;
  pInfo = (struct lockInfo*)sqliteHashFind(&lockHash, &key, sizeof(key));
  if( pInfo==0 ){
    pInfo = sqliteMalloc( sizeof(*pInfo) );
    pInfo->key = key;
    pInfo->nRef = 1;
    pInfo->cnt = 0;
    sqliteHashInsert(&lockHash, &pInfo->key, sizeof(key), pInfo);
  }else{
    pInfo->nRef++;
  }
  return pInfo;
}

/*
** Release a lockInfo structure previously allocated by findLockInfo().
*/
static void releaseLockInfo(struct lockInfo *pInfo){
  pInfo->nRef--;
  if( pInfo->nRef==0 ){
    sqliteHashInsert(&lockHash, &pInfo->key, sizeof(pInfo->key), 0);
    sqliteFree(pInfo);
  }
}
#endif


/*
** Delete the named file
*/
int sqliteOsDelete(const char *zFilename){
#if OS_UNIX
  unlink(zFilename);
................................................................................
*/
int sqliteOsOpenReadWrite(
  const char *zFilename,
  OsFile *pResult,
  int *pReadonly
){
#if OS_UNIX
  OsFile s;
  s.fd = open(zFilename, O_RDWR|O_CREAT, 0644);
  if( s.fd<0 ){
    s.fd = open(zFilename, O_RDONLY);
    if( s.fd<0 ){
      return SQLITE_CANTOPEN; 
    }
    *pReadonly = 1;
  }else{
    *pReadonly = 0;
  }
  sqliteOsEnterMutex();
  s.pLock = findLockInfo(s.fd);
  sqliteOsLeaveMutex();
  if( s.pLock==0 ){
    close(s.fd);
    return SQLITE_NOMEM;
  }
  *pResult = s;
  return SQLITE_OK;
#endif
#if OS_WIN
  HANDLE h = CreateFile(zFilename,
     GENERIC_READ | GENERIC_WRITE,
     FILE_SHARE_READ | FILE_SHARE_WRITE,
     NULL,
................................................................................
**
** On success, write the file handle into *pResult and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqliteOsOpenExclusive(const char *zFilename, OsFile *pResult){
#if OS_UNIX
  OsFile s;
  if( access(zFilename, 0)==0 ){
    return SQLITE_CANTOPEN;
  }
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif
  s.fd = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600);
  if( s.fd<0 ){
    return SQLITE_CANTOPEN;
  }
  sqliteOsEnterMutex();
  s.pLock = findLockInfo(s.fd);
  sqliteOsLeaveMutex();
  if( s.pLock==0 ){
    close(s.fd);
    return SQLITE_NOMEM;
  }
  *pResult = s;
  return SQLITE_OK;
#endif
#if OS_WIN
  HANDLE h = CreateFile(zFilename,
     GENERIC_READ | GENERIC_WRITE,
     0,
     NULL,
................................................................................
**
** On success, write the file handle into *pResult and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqliteOsOpenReadOnly(const char *zFilename, OsFile *pResult){
#if OS_UNIX
  OsFile s;
  s.fd = open(zFilename, O_RDONLY);
  if( s.fd<0 ){
    return SQLITE_CANTOPEN;
  }
  sqliteOsEnterMutex();
  s.pLock = findLockInfo(s.fd);
  sqliteOsLeaveMutex();
  if( s.pLock==0 ){
    close(s.fd);
    return SQLITE_NOMEM;
  }
  *pResult = s;
  return SQLITE_OK;
#endif
#if OS_WIN
  HANDLE h = CreateFile(zFilename,
     GENERIC_READ,
     0,
     NULL,
................................................................................
    zDir = azDirs[i];
    break;
  }
  do{
    sprintf(zBuf, "%s/sqlite_", zDir);
    j = strlen(zBuf);
    for(i=0; i<15; i++){
      int n = sqliteRandomByte() % (sizeof(zChars)-1);
      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; 
................................................................................
}

/*
** Close a file
*/
int sqliteOsClose(OsFile id){
#if OS_UNIX
  close(id.fd);
  sqliteOsEnterMutex();
  releaseLockInfo(id.pLock);
  sqliteOsLeaveMutex();
  return SQLITE_OK;
#endif
#if OS_WIN
  CloseHandle(id);
  return SQLITE_OK;
#endif
}
................................................................................
/*
** Read data from a file into a buffer.  Return the number of
** bytes actually read.
*/
int sqliteOsRead(OsFile id, void *pBuf, int amt){
#if OS_UNIX
  int got;
  got = read(id.fd, pBuf, amt);
  if( got<0 ) got = 0;
  return got==amt ? SQLITE_OK : SQLITE_IOERR;
#endif
#if OS_WIN
  DWORD got;
  if( !ReadFile(id, pBuf, amt, &got, 0) ){
    got = 0;
................................................................................
/*
** Write data from a buffer into a file.  Return SQLITE_OK on success
** or some other error code on failure.
*/
int sqliteOsWrite(OsFile id, const void *pBuf, int amt){
#if OS_UNIX
  int wrote;
  wrote = write(id.fd, pBuf, amt);
  if( wrote<amt ) return SQLITE_FULL;
  return SQLITE_OK;
#endif
#if OS_WIN
  DWORD wrote;
  if( !WriteFile(id, pBuf, amt, &wrote, 0) || wrote<amt ){
    return SQLITE_FULL;
................................................................................
}

/*
** Move the read/write pointer in a file.
*/
int sqliteOsSeek(OsFile id, int offset){
#if OS_UNIX
  lseek(id.fd, offset, SEEK_SET);
  return SQLITE_OK;
#endif
#if OS_WIN
  SetFilePointer(id, offset, 0, FILE_BEGIN);
  return SQLITE_OK;
#endif
}

/*
** Make sure all writes to a particular file are committed to disk.
*/
int sqliteOsSync(OsFile id){
#if OS_UNIX
  return fsync(id.fd)==0 ? SQLITE_OK : SQLITE_IOERR;
#endif
#if OS_WIN
  return FlushFileBuffers(id) ? SQLITE_OK : SQLITE_IOERR;
#endif
}

/*
** Truncate an open file to a specified size
*/
int sqliteOsTruncate(OsFile id, int nByte){
#if OS_UNIX
  return ftruncate(id.fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
#endif
#if OS_WIN
  SetFilePointer(id, nByte, 0, FILE_BEGIN);
  SetEndOfFile(id);
  return SQLITE_OK;
#endif
}
................................................................................

/*
** Determine the current size of a file in bytes
*/
int sqliteOsFileSize(OsFile id, int *pSize){
#if OS_UNIX
  struct stat buf;
  if( fstat(id.fd, &buf)!=0 ){
    return SQLITE_IOERR;
  }
  *pSize = buf.st_size;
  return SQLITE_OK;
#endif
#if OS_WIN
  *pSize = GetFileSize(id, 0);
  return SQLITE_OK;
#endif
}


/*
** Get a read or write lock on a file.
*/
int sqliteOsLock(OsFile id, int wrlock){
#if OS_UNIX
  int rc;
  int needSysLock;
  sqliteOsEnterMutex();
  if( wrlock ){
    if( id.pLock->cnt!=0 ){
      rc = SQLITE_BUSY;
    }else{
      rc = SQLITE_OK;
      id.pLock->cnt = -1;
      needSysLock = 1;
    }
  }else{
    if( id.pLock<0 ){
      rc = SQLITE_BUSY;
    }else{
      rc = SQLITE_OK;
      needSysLock = id.pLock->cnt==0;
      id.pLock->cnt++;
    }
  }
  sqliteOsLeaveMutex();      
  if( rc==SQLITE_OK && needSysLock ){ 
    struct flock lock;
    lock.l_type = wrlock ? F_WRLCK : F_RDLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = lock.l_len = 0L;
    rc = fcntl(id.fd, F_SETLK, &lock)==0 ? SQLITE_OK : SQLITE_BUSY;


  }
  return rc;
#endif
#if OS_WIN
  if( !LockFile(id, 0, 0, 1024, 0) ){
    return SQLITE_BUSY;
  }
  return SQLITE_OK;
#endif
................................................................................

/*
** Release the read or write lock from a file.
*/
int sqliteOsUnlock(OsFile id){
#if OS_UNIX
  int rc;
  int needSysUnlock;

  sqliteOsEnterMutex();
  if( id.pLock->cnt<0 ){
    needSysUnlock = 1;
    id.pLock->cnt = 0;
  }else if( id.pLock->cnt>0 ){
    id.pLock->cnt--;
    needSysUnlock = id.pLock->cnt==0;
  }else{
    rc = SQLITE_OK;
    needSysUnlock = 0;
  }
  sqliteOsLeaveMutex();
  if( needSysUnlock ){
    struct flock lock;
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = lock.l_len = 0L;

    rc = fcntl(id.fd, F_SETLK, &lock)==0 ? SQLITE_OK : SQLITE_IOERR;
  }
  return rc;
#endif
#if OS_WIN
  return UnlockFile(id, 0, 0, 1024, 0) ? SQLITE_OK : SQLITE_IOERR;
#endif
}

/*
................................................................................
#endif
#endif
#if OS_WIN
  Sleep(ms);
  return ms;
#endif
}

/*
** The following pair of routine implement mutual exclusion for
** multi-threaded processes.  Only a single thread is allowed to
** executed code that is surrounded by EnterMutex() and LeaveMutex().
**
** SQLite uses only a single Mutex.  There is not much critical
** code and what little there is executes quickly and without blocking.
**
****** TBD:  The mutex is currently unimplemented.  Until it is
****** implemented, SQLite is not threadsafe.
*/
static int inMutex = 0;
void sqliteOsEnterMutex(){
  assert( !inMutex );
  inMutex = 1;
}
void sqliteOsLeaveMutex(){
  assert( inMutex );
  inMutex = 0;
}

Changes to src/os.h.

17
18
19
20
21
22
23

24



25
26
27
28
29
30
31
..
51
52
53
54
55
56
57


58
59
60
61
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_

/*
** A handle for an open file is stored in an OsFile object.
*/
#if OS_UNIX

  typedef int OsFile;



# define SQLITE_TEMPNAME_SIZE 200
# if defined(HAVE_USLEEP) && HAVE_USLEEP
#  define SQLITE_MIN_SLEEP_MS 1
# else
#  define SQLITE_MIN_SLEEP_MS 1000
# endif
#endif
................................................................................
int sqliteOsSync(OsFile);
int sqliteOsTruncate(OsFile, int size);
int sqliteOsFileSize(OsFile, int *pSize);
int sqliteOsLock(OsFile, int wrlock);
int sqliteOsUnlock(OsFile);
int sqliteOsRandomSeed(char*);
int sqliteOsSleep(int ms);





#endif /* _SQLITE_OS_H_ */







>
|
>
>
>







 







>
>




17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
..
55
56
57
58
59
60
61
62
63
64
65
66
67
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_

/*
** A handle for an open file is stored in an OsFile object.
*/
#if OS_UNIX
  typedef struct OsFile OsFile;
  struct OsFile {
    struct lockInfo *pLock;  /* Information about locks on this inode */
    int fd;                  /* The file descriptor */
  };
# define SQLITE_TEMPNAME_SIZE 200
# if defined(HAVE_USLEEP) && HAVE_USLEEP
#  define SQLITE_MIN_SLEEP_MS 1
# else
#  define SQLITE_MIN_SLEEP_MS 1000
# endif
#endif
................................................................................
int sqliteOsSync(OsFile);
int sqliteOsTruncate(OsFile, int size);
int sqliteOsFileSize(OsFile, int *pSize);
int sqliteOsLock(OsFile, int wrlock);
int sqliteOsUnlock(OsFile);
int sqliteOsRandomSeed(char*);
int sqliteOsSleep(int ms);
void sqliteOsEnterMutex();
void sqliteOsLeaveMutex();



#endif /* _SQLITE_OS_H_ */

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
*************************************************************************
** 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;
}







|





|
>

<
>

>
>
>
>
>
>
>
>
>










|


|
|


|



|
|
|
|

|




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






|


>
|

|

>


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
*************************************************************************
** 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.8 2001/10/09 04:19:47 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** Get a single 8-bit random value from the RC4 PRNG.  The Mutex
** must be held while executing this routine.
*/

static int randomByte(){
  int t;

  /* All threads share a single random number generator.
  ** This structure is the current state of the generator.
  */
  static struct {
    int isInit;          /* True if initialized */
    int i, j;            /* State variables */
    int s[256];          /* State variables */
  } prng;

  /* 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( !prng.isInit ){
    int i;
    char k[256];
    prng.j = 0;
    prng.i = 0;
    sqliteOsRandomSeed(k);
    for(i=0; i<256; i++){
      prng.s[i] = i;
    }
    for(i=0; i<256; i++){
      int t;
      prng.j = (prng.j + prng.s[i] + k[i]) & 0xff;
      t = prng.s[prng.j];
      prng.s[prng.j] = prng.s[i];
      prng.s[i] = t;
    }
    prng.isInit = 1;
  }

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

/*
** Return an random 8-bit integer.
*/
int sqliteRandomByte(){
  int r;
  sqliteOsEnterMutex();
  r = randomByte();
  sqliteOsLeaveMutex();
  return r;
}

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

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
462
463
464
465
466
467
468
469
470
471
472
473
474
**    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.58 2001/10/08 13:22:33 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 */
................................................................................
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 *, ...);







|







 







<
<
<
<
<







 







|
|




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





152
153
154
155
156
157
158
...
457
458
459
460
461
462
463
464
465
466
467
468
469
**    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.59 2001/10/09 04:19:47 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 */





  int nextRowid;                /* Next generated rowID */
};

/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
................................................................................
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();
int sqliteRandomInteger();
void sqliteBeginTransaction(Parse*);
void sqliteCommitTransaction(Parse*);
void sqliteRollbackTransaction(Parse*);
char *sqlite_mprintf(const char *, ...);

Changes to src/tokenize.c.

11
12
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
...
109
110
111
112
113
114
115


116
117
118
119
120
121
122
123
124
125


126
127
128
129
130
131
132
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.25 2001/10/08 13:22:33 drh Exp $
*/
#include "sqliteInt.h"

#include <ctype.h>
#include <stdlib.h>

/*
** All the keywords of the SQL language are stored as in a hash
** table composed of instances of the following structure.
*/
................................................................................
** returned.  If the input is not a keyword, TK_ID is returned.
*/
static int sqliteKeywordCode(const char *z, int n){
  int h;
  Keyword *p;
  if( aKeywordTable[0].len==0 ){
    /* Initialize the keyword hash table */


    int i;
    int n;
    n = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
    for(i=0; i<n; i++){
      aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
      h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
      h %= KEY_HASH_SIZE;
      aKeywordTable[i].pNext = apHashTable[h];
      apHashTable[h] = &aKeywordTable[i];
    }


  }
  h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
  for(p=apHashTable[h]; p; p=p->pNext){
    if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
      return p->tokenType;
    }
  }







|


>







 







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







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.26 2001/10/09 04:19:47 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>

/*
** All the keywords of the SQL language are stored as in a hash
** table composed of instances of the following structure.
*/
................................................................................
** returned.  If the input is not a keyword, TK_ID is returned.
*/
static int sqliteKeywordCode(const char *z, int n){
  int h;
  Keyword *p;
  if( aKeywordTable[0].len==0 ){
    /* Initialize the keyword hash table */
    sqliteOsEnterMutex();
    if( aKeywordTable[0].len==0 ){
      int i;
      int n;
      n = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
      for(i=0; i<n; i++){
        aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
        h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
        h %= KEY_HASH_SIZE;
        aKeywordTable[i].pNext = apHashTable[h];
        apHashTable[h] = &aKeywordTable[i];
      }
    }
    sqliteOsLeaveMutex();
  }
  h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
  for(p=apHashTable[h]; p; p=p->pNext){
    if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
      return p->tokenType;
    }
  }

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
** 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.81 2001/10/08 13:22:33 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
................................................................................
    ** to double the speed of the COPY operation.
    */
    int res, rx, cnt, x;
    cnt = 0;
    v = db->nextRowid;
    do{
      if( cnt>5 ){
        v = sqliteRandomInteger(db);
      }else{
        v += sqliteRandomByte(db) + 1;
      }
      if( v==0 ) continue;
      x = bigEndian(v);
      rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, &x, sizeof(int), &res);
      cnt++;
    }while( cnt<1000 && rx==SQLITE_OK && res==0 );
    db->nextRowid = v;







|







 







|

|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
** 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.82 2001/10/09 04:19:47 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
................................................................................
    ** to double the speed of the COPY operation.
    */
    int res, rx, cnt, x;
    cnt = 0;
    v = db->nextRowid;
    do{
      if( cnt>5 ){
        v = sqliteRandomInteger();
      }else{
        v += sqliteRandomByte() + 1;
      }
      if( v==0 ) continue;
      x = bigEndian(v);
      rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, &x, sizeof(int), &res);
      cnt++;
    }while( cnt<1000 && rx==SQLITE_OK && res==0 );
    db->nextRowid = v;

Changes to test/lock.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50
51
52
..
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
#    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
#
................................................................................
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}
do_test lock-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {t1}
do_test lock-1.4 {
  set r [catch {execsql {
     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
  } db2} msg]
  lappend r $msg
} {1 {database schema has changed}}
do_test lock-1.5 {
  set r [catch {execsql {

     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
  } db2} msg]
  lappend r $msg
} {0 t1}

do_test lock-1.6 {
  execsql {INSERT INTO t1 VALUES(1,2)}
  execsql {SELECT * FROM t1}
} {1 2}
do_test lock-1.7 {
................................................................................
do_test lock-1.8 {
  execsql {UPDATE t1 SET a=b, b=a} db2
  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 {
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
} {1 {database is locked}}
do_test lock-1.12 {
  execsql {ROLLBACK}
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
} {0 {2 1}}

do_test lock-1.13 {
  execsql {CREATE TABLE t2(x int, y int)}
  execsql {INSERT INTO t2 VALUES(8,9)}
  execsql {SELECT * FROM t2}
} {8 9}
do_test lock-1.14 {
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
} {1 {database schema has changed}}
do_test lock-1.15 {
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
  lappend r $msg
} {0 {8 9}}

do_test lock-1.16 {
  db eval {SELECT * FROM t1} qv {
    set x [db eval {SELECT * FROM t1}]
  }
  set x







|







 







|
|
|
<


<
>

|
<







 







<





|
<



|
<








|
<


|
<







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
29
30
31
32
33
34
35
36
37
38

39
40

41
42
43

44
45
46
47
48
49
50
..
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
#    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.13 2001/10/09 04:19:47 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}
do_test lock-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {t1}
do_test lock-1.4 {
  catchsql {
    SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
  } db2

} {1 {database schema has changed}}
do_test lock-1.5 {

  catchsql {
     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
  } db2

} {0 t1}

do_test lock-1.6 {
  execsql {INSERT INTO t1 VALUES(1,2)}
  execsql {SELECT * FROM t1}
} {1 2}
do_test lock-1.7 {
................................................................................
do_test lock-1.8 {
  execsql {UPDATE t1 SET a=b, b=a} db2
  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}
  catchsql {SELECT * FROM t1}

} {0 {2 1}}

do_test lock-1.13 {
  execsql {CREATE TABLE t2(x int, y int)}
  execsql {INSERT INTO t2 VALUES(8,9)}
  execsql {SELECT * FROM t2}
} {8 9}
do_test lock-1.14 {
  catchsql {SELECT * FROM t1} db2

} {1 {database schema has changed}}
do_test lock-1.15 {
  catchsql {SELECT * FROM t2} db2

} {0 {8 9}}

do_test lock-1.16 {
  db eval {SELECT * FROM t1} qv {
    set x [db eval {SELECT * FROM t1}]
  }
  set x

Changes to test/temptable.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
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
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for temporary tables and indices.
#
# $Id: temptable.test,v 1.1 2001/10/08 13:22:33 drh Exp $

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

# Create an alternative connection to the database
#
do_test temptable-1.0 {
................................................................................
  execsql {INSERT INTO t1 VALUES(1,2,3);}
  execsql {SELECT * FROM t1}
} {1 2 3}
do_test temptable-1.2 {
  catch {db2 eval {SELECT * FROM sqlite_master}}
  db2 eval {SELECT * FROM t1}
} {1 2 3}
do_test testtable-1.3 {
  execsql {SELECT name FROM sqlite_master}
} {t1}
do_test testtable-1.4 {
  db2 eval {SELECT name FROM sqlite_master}
} {t1}

# Create a temporary table.  Verify that only one of the two
# processes can see it.
#
do_test testtable-1.5 {
  db2 eval {
    CREATE TEMP TABLE t2(x,y,z);
    INSERT INTO t2 VALUES(4,5,6);
  }
  db2 eval {SELECT * FROM t2}
} {4 5 6}
do_test testtable-1.6 {
  catch {execsql {SELECT * FROM sqlite_master}}
  catchsql {SELECT * FROM t2}
} {1 {no such table: t2}}
do_test testtable-1.7 {
  catchsql {INSERT INTO t2 VALUES(8,9,0);}
} {1 {no such table: t2}}
do_test testtable-1.8 {
  db2 eval {INSERT INTO t2 VALUES(8,9,0);}
  db2 eval {SELECT * FROM t2 ORDER BY x}
} {4 5 6 8 9 0}
do_test testtable-1.9 {
  db2 eval {DELETE FROM t2 WHERE x==8}
  db2 eval {SELECT * FROM t2 ORDER BY x}
} {4 5 6}
do_test testtable-1.10 {
  db2 eval {DELETE FROM t2}
  db2 eval {SELECT * FROM t2}
} {}
do_test testtable-1.11 {
  db2 eval {
     INSERT INTO t2 VALUES(7,6,5);
     INSERT INTO t2 VALUES(4,3,2);
     SELECT * FROM t2 ORDER BY x;
  }
} {4 3 2 7 6 5}
do_test testtable-1.12 {
  db2 eval {DROP TABLE t2;}
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {1 {no such table: t2}}

# Make sure temporary tables work with transactions
#
do_test testtable-2.1 {
  execsql {
    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE t2(x,y);
    INSERT INTO t2 VALUES(1,2);
    SELECT * FROM t2;
  }
} {1 2}
do_test testtable-2.2 {
  execsql {ROLLBACK}
  catchsql {SELECT * FROM t2}
} {1 {no such table: t2}}
do_test testtable-2.3 {
  execsql {
    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE t2(x,y);
    INSERT INTO t2 VALUES(1,2);
    SELECT * FROM t2;
  }
} {1 2}
do_test testtable-2.4 {
  execsql {COMMIT}
  catchsql {SELECT * FROM t2}
} {0 {1 2}}
do_test testtable-2.5 {
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {1 {no such table: t2}}





























# Check for correct name collision processing. A name collision can
# occur when process A creates a temporary table T then process B
# creates a permanent table also named T.  The temp table in process A
# hides the existance of the permanent table.
#














































































finish_test







|







 







|


|






|






|



|


|



|



|



|






|







|







|



|







|



|





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





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

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for temporary tables and indices.
#
# $Id: temptable.test,v 1.2 2001/10/09 04:19:47 drh Exp $

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

# Create an alternative connection to the database
#
do_test temptable-1.0 {
................................................................................
  execsql {INSERT INTO t1 VALUES(1,2,3);}
  execsql {SELECT * FROM t1}
} {1 2 3}
do_test temptable-1.2 {
  catch {db2 eval {SELECT * FROM sqlite_master}}
  db2 eval {SELECT * FROM t1}
} {1 2 3}
do_test temptable-1.3 {
  execsql {SELECT name FROM sqlite_master}
} {t1}
do_test temptable-1.4 {
  db2 eval {SELECT name FROM sqlite_master}
} {t1}

# Create a temporary table.  Verify that only one of the two
# processes can see it.
#
do_test temptable-1.5 {
  db2 eval {
    CREATE TEMP TABLE t2(x,y,z);
    INSERT INTO t2 VALUES(4,5,6);
  }
  db2 eval {SELECT * FROM t2}
} {4 5 6}
do_test temptable-1.6 {
  catch {execsql {SELECT * FROM sqlite_master}}
  catchsql {SELECT * FROM t2}
} {1 {no such table: t2}}
do_test temptable-1.7 {
  catchsql {INSERT INTO t2 VALUES(8,9,0);}
} {1 {no such table: t2}}
do_test temptable-1.8 {
  db2 eval {INSERT INTO t2 VALUES(8,9,0);}
  db2 eval {SELECT * FROM t2 ORDER BY x}
} {4 5 6 8 9 0}
do_test temptable-1.9 {
  db2 eval {DELETE FROM t2 WHERE x==8}
  db2 eval {SELECT * FROM t2 ORDER BY x}
} {4 5 6}
do_test temptable-1.10 {
  db2 eval {DELETE FROM t2}
  db2 eval {SELECT * FROM t2}
} {}
do_test temptable-1.11 {
  db2 eval {
     INSERT INTO t2 VALUES(7,6,5);
     INSERT INTO t2 VALUES(4,3,2);
     SELECT * FROM t2 ORDER BY x;
  }
} {4 3 2 7 6 5}
do_test temptable-1.12 {
  db2 eval {DROP TABLE t2;}
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {1 {no such table: t2}}

# Make sure temporary tables work with transactions
#
do_test temptable-2.1 {
  execsql {
    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE t2(x,y);
    INSERT INTO t2 VALUES(1,2);
    SELECT * FROM t2;
  }
} {1 2}
do_test temptable-2.2 {
  execsql {ROLLBACK}
  catchsql {SELECT * FROM t2}
} {1 {no such table: t2}}
do_test temptable-2.3 {
  execsql {
    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE t2(x,y);
    INSERT INTO t2 VALUES(1,2);
    SELECT * FROM t2;
  }
} {1 2}
do_test temptable-2.4 {
  execsql {COMMIT}
  catchsql {SELECT * FROM t2}
} {0 {1 2}}
do_test temptable-2.5 {
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {1 {no such table: t2}}


# Make sure indices on temporary tables are also temporary.
#
do_test temptable-3.1 {
  execsql {
    CREATE INDEX i2 ON t2(x);
    SELECT name FROM sqlite_master WHERE type='index';
  }
} {}
do_test temptable-3.2 {
  execsql {
    SELECT y FROM t2 WHERE x=1;
  }
} {2}
do_test temptable-3.3 {
  execsql {
    DROP INDEX i2;
    SELECT y FROM t2 WHERE x=1;
  }
} {2}
do_test temptable-3.4 {
  execsql {
    CREATE INDEX i2 ON t2(x);
    DROP TABLE t2;
  }
  catchsql {DROP INDEX i2}
} {1 {no such index: i2}}

# Check for correct name collision processing. A name collision can
# occur when process A creates a temporary table T then process B
# creates a permanent table also named T.  The temp table in process A
# hides the existance of the permanent table.
#
do_test temptable-4.1 {
  db2 eval {
    CREATE TEMP TABLE t2(x,y);
    INSERT INTO t2 VALUES(10,20);
    SELECT * FROM t2;
  }
} {10 20}
do_test temptable-4.2 {
  execsql {
    CREATE TABLE t2(x,y,z);
    INSERT INTO t2 VALUES(9,8,7);
    SELECT * FROM t2;
  }
} {9 8 7}
do_test temptable-4.3 {
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {1 {database schema has changed}}
do_test temptable-4.4 {
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {0 {10 20}}
do_test temptable-4.5 {
  db2 eval {DROP TABLE t2}
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {1 {no such table: t2}}
do_test temptable-4.6 {
  db2 close
  sqlite db2 ./test.db
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {0 {9 8 7}}

# Now create a temporary table in db2 and a permanent index in db.  The
# temporary table in db2 should mask the name of the permanent index,
# but the permanent index should still be accessible and should still
# be updated when its correspnding table changes.
#
do_test temptable-5.1 {
  db2 eval {CREATE TEMP TABLE mask(a,b,c)}
  execsql {
    CREATE INDEX mask ON t2(x);
    SELECT * FROM t2;
  }
} {9 8 7}
do_test temptable-5.2 {
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {1 {database schema has changed}}
do_test temptable-5.3 {
  set r [catch {db2 eval {SELECT * FROM t2}} msg]
  lappend r $msg
} {0 {9 8 7}}
do_test temptable-5.4 {
  execsql {SELECT y FROM t2 WHERE x=9}
} {8}
do_test temptable-5.5 {
  db2 eval {SELECT y FROM t2 WHERE x=9}
} {8}
do_test temptable-5.6 {
  db2 eval {
    INSERT INTO t2 VALUES(1,2,3);
    SELECT y FROM t2 WHERE x=1;
  }
} {2}
do_test temptable-5.7 {
  db2 eval {SELECT y FROM t2 WHERE x=9}
} {8}
do_test temptable-5.8 {
  execsql {
    SELECT y FROM t2 WHERE x=1;
  }
} {2}
do_test temptable-5.9 {
  execsql {SELECT y FROM t2 WHERE x=9}
} {8}

finish_test

Changes to www/changes.tcl.

13
14
15
16
17
18
19
20

21
22
23
24
25


26
27
28
29
30
31
32


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

chng {2001 Oct ? (2.0.2)} {

<li>Removed some unused "#include <unistd.h>" that were causing problems
    for VC++.</li>
<li>Fixed <b>sqlite.h</b> so that it is usable from C++</li>
<li>Added the FULL_COLUMN_NAMES pragma.  When set to "ON", the names of
    columns are reported back as TABLE.COLUMN instead of just COLUMN.</li>


<li>Added support for TEMPORARY tables and indices.</li>
}

chng {2001 Oct 2 (2.0.1)} {
<li>Remove some C++ style comments from btree.c so that it will compile
    using compilers other than gcc.</li>
<li>The ".dump" output from the shell does not work if there are embedded







|
>





>
>







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


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

chng {2001 Oct 8 (2.0.2)} {
<li>Fix a bugs in the locking protocol.</li>
<li>Removed some unused "#include <unistd.h>" that were causing problems
    for VC++.</li>
<li>Fixed <b>sqlite.h</b> so that it is usable from C++</li>
<li>Added the FULL_COLUMN_NAMES pragma.  When set to "ON", the names of
    columns are reported back as TABLE.COLUMN instead of just COLUMN.</li>
<li>Added the TABLE_INFO() and INDEX_INFO() pragmas to help support the
    ODBC interface.</li>
<li>Added support for TEMPORARY tables and indices.</li>
}

chng {2001 Oct 2 (2.0.1)} {
<li>Remove some C++ style comments from btree.c so that it will compile
    using compilers other than gcc.</li>
<li>The ".dump" output from the shell does not work if there are embedded