/ Changes On Branch apple-osx
Login

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

Changes In Branch apple-osx Excluding Merge-Ins

This is equivalent to a diff from 3bfa9cc9 to 1240ee4f

2020-02-01
14:29
Fix a problem in sqlite3CodecQueryParameters() that was introduced by the query parameter encoding changes for the 3.31.1 release. (Leaf check-in: 1240ee4f user: drh tags: apple-osx)
13:30
Fix a problem in sqlite3CodecQueryParameters() that was introduced by the query parameter encoding changes for the 3.31.1 release. (check-in: cc65ca54 user: drh tags: branch-3.31)
00:08
Merge version 3.31.1 (check-in: d250d085 user: numist tags: apple-osx)
2020-01-28
15:02
Minor change for compatibility with the s390 architecture. (check-in: 04885763 user: drh tags: trunk)
2020-01-27
19:55
Version 3.31.1 (check-in: 3bfa9cc9 user: drh tags: trunk, release, version-3.31.1)
17:09
Update the version number to 3.31.1. (check-in: 6fb9a8fb user: drh tags: trunk)

Changes to Makefile.in.

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
349
350
351
352
353
354
355



356
357
358
359
360
361
362
...
566
567
568
569
570
571
572











573
574
575
576
577
578
579
...
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
....
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433

# The library that programs using readline() must link against.
#
LIBREADLINE = @TARGET_READLINE_LIBS@

# Should the database engine be compiled threadsafe
#
TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@

# Any target libraries which libsqlite must be linked against
#
TLIBS = @LIBS@ $(LIBS)

# Flags controlling use of the in memory btree implementation
#
................................................................................
# This is the command to use for tclsh - normally just "tclsh", but we may
# know the specific version we want to use
#
TCLSH_CMD = @TCLSH_CMD@

# Where do we want to install the tcl plugin
#
TCLLIBDIR = @TCLLIBDIR@

# The suffix used on shared libraries.  Ex:  ".dll", ".so", ".dylib"
#
SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@

# If gcov support was enabled by the configure script, add the appropriate
# flags here.  It's not always as easy as just having the user add the right
................................................................................
SRC += \
  $(TOP)/ext/icu/sqliteicu.h \
  $(TOP)/ext/icu/icu.c
SRC += \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/rtree.c \
  $(TOP)/ext/rtree/geopoly.c



SRC += \
  $(TOP)/ext/session/sqlite3session.c \
  $(TOP)/ext/session/sqlite3session.h
SRC += \
  $(TOP)/ext/userauth/userauth.c \
  $(TOP)/ext/userauth/sqlite3userauth.h
SRC += \
................................................................................
  $(TOP)/ext/rtree/geopoly.c
EXTHDR += \
  $(TOP)/ext/icu/sqliteicu.h
EXTHDR += \
  $(TOP)/ext/rtree/sqlite3rtree.h
EXTHDR += \
  $(TOP)/ext/userauth/sqlite3userauth.h












# executables needed for testing
#
TESTPROGS = \
  testfixture$(TEXE) \
  sqlite3$(TEXE) \
  sqlite3_analyzer$(TEXE) \
................................................................................
libsqlite3.la:	$(LIBOBJ)
	$(LTLINK) -no-undefined -o $@ $(LIBOBJ) $(TLIBS) \
		${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8"

libtclsqlite3.la:	tclsqlite.lo libsqlite3.la
	$(LTLINK) -no-undefined -o $@ tclsqlite.lo \
		libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \
		-rpath "$(TCLLIBDIR)" \
		-version-info "8:6:8" \
		-avoid-version

sqlite3$(TEXE):	shell.c sqlite3.c
	$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
		shell.c sqlite3.c \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

sqldiff$(TEXE):	$(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h
................................................................................
	$(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
	$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)

pkgIndex.tcl:
	echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@
tcl_install:	lib_install libtclsqlite3.la pkgIndex.tcl
	$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
	$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
	rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
	$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)

clean:
	rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps
	rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
	rm -f mkkeywordhash$(BEXE) keywordhash.h







|







 







|







 







>
>
>







 







>
>
>
>
>
>
>
>
>
>
>







 







|
|
<







 







|
|
|
|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
...
650
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665
....
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446

# The library that programs using readline() must link against.
#
LIBREADLINE = @TARGET_READLINE_LIBS@

# Should the database engine be compiled threadsafe
#
#TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@

# Any target libraries which libsqlite must be linked against
#
TLIBS = @LIBS@ $(LIBS)

# Flags controlling use of the in memory btree implementation
#
................................................................................
# This is the command to use for tclsh - normally just "tclsh", but we may
# know the specific version we want to use
#
TCLSH_CMD = @TCLSH_CMD@

# Where do we want to install the tcl plugin
#
TCLLIBDIR = /System/Library/Tcl

# The suffix used on shared libraries.  Ex:  ".dll", ".so", ".dylib"
#
SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@

# If gcov support was enabled by the configure script, add the appropriate
# flags here.  It's not always as easy as just having the user add the right
................................................................................
SRC += \
  $(TOP)/ext/icu/sqliteicu.h \
  $(TOP)/ext/icu/icu.c
SRC += \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/rtree.c \
  $(TOP)/ext/rtree/geopoly.c
SRC += \
  $(TOP)/ext/sqlrr/sqlrr.h \
  $(TOP)/ext/sqlrr/sqlrr.c
SRC += \
  $(TOP)/ext/session/sqlite3session.c \
  $(TOP)/ext/session/sqlite3session.h
SRC += \
  $(TOP)/ext/userauth/userauth.c \
  $(TOP)/ext/userauth/sqlite3userauth.h
SRC += \
................................................................................
  $(TOP)/ext/rtree/geopoly.c
EXTHDR += \
  $(TOP)/ext/icu/sqliteicu.h
EXTHDR += \
  $(TOP)/ext/rtree/sqlite3rtree.h
EXTHDR += \
  $(TOP)/ext/userauth/sqlite3userauth.h
EXTHDR += \
  $(TOP)/ext/sqlrr/sqlrr.h

# If using the amalgamation, use sqlite3.c directly to build the test
# fixture.  Otherwise link against libsqlite3.la.  (This distinction is
# necessary because the test fixture requires non-API symbols which are
# hidden when the library is built via the amalgamation).
#
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c $(TESTFIXTURE_SRC$(USE_AMALGAMATION))

# executables needed for testing
#
TESTPROGS = \
  testfixture$(TEXE) \
  sqlite3$(TEXE) \
  sqlite3_analyzer$(TEXE) \
................................................................................
libsqlite3.la:	$(LIBOBJ)
	$(LTLINK) -no-undefined -o $@ $(LIBOBJ) $(TLIBS) \
		${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8"

libtclsqlite3.la:	tclsqlite.lo libsqlite3.la
	$(LTLINK) -no-undefined -o $@ tclsqlite.lo \
		libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \
                -rpath "$(TCLLIBDIR)/sqlite3" \
		-version-info "8:6:8"


sqlite3$(TEXE):	shell.c sqlite3.c
	$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
		shell.c sqlite3.c \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

sqldiff$(TEXE):	$(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h
................................................................................
	$(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
	$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)

pkgIndex.tcl:
	echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@
tcl_install:	lib_install libtclsqlite3.la pkgIndex.tcl
	$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)/sqlite3
	$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/sqlite3
	rm -f $(DESTDIR)$(TCLLIBDIR)/sqlite3/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/sqlite3/libtclsqlite3.a
	$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)/sqlite3

clean:
	rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps
	rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
	rm -f mkkeywordhash$(BEXE) keywordhash.h

Changes to ext/fts5/test/fts5misc.test.

320
321
322
323
324
325
326
327
  SELECT * FROM ft NATURAL JOIN t1 WHERE ft MATCH('b')
} {b world {}}
do_execsql_test 12.3 {
  SELECT * FROM t2 JOIN ft USING (ft)
} {3 4 b b}

finish_test








<
320
321
322
323
324
325
326

  SELECT * FROM ft NATURAL JOIN t1 WHERE ft MATCH('b')
} {b world {}}
do_execsql_test 12.3 {
  SELECT * FROM t2 JOIN ft USING (ft)
} {3 4 b b}

finish_test

Changes to ext/rtree/rtree.c.

78
79
80
81
82
83
84

85
86
87
88
89
90
91
# undef NDEBUG
#endif
#endif

#include <string.h>
#include <stdio.h>
#include <assert.h>


/*  The following macro is used to suppress compiler warnings.
*/
#ifndef UNUSED_PARAMETER
# define UNUSED_PARAMETER(x) (void)(x)
#endif








>







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# undef NDEBUG
#endif
#endif

#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdint.h>

/*  The following macro is used to suppress compiler warnings.
*/
#ifndef UNUSED_PARAMETER
# define UNUSED_PARAMETER(x) (void)(x)
#endif

Added ext/sqlrr/README.txt.













































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

sqlrr - 10/19/2009

SQL Replay Recording

SUMMARY
-------------------------------------------------------
This extension enables recording sqlite API calls that access the database so that they can be replayed or examined.

USAGE
------------------------------------------------------
Recording is enabled by compiling sqlite with symbolic constant SQLITE_ENABLE_SQLRR defined.  
By default logs are written to /tmp/<databasename>_<pid>_<connection_number>.sqlrr, to choose another directory, set the environment variable SQLITE_REPLAY_RECORD_DIR to that path.

FILE FORMAT
-----------------------------------------------------
 file:			<header>[<sql-command>]*
 
 header:			<signature><format-version>
   signature: 		SQLRR (5 bytes)
   format-version:	n (1 byte)
 
 sql-command:		<timestamp><type><arg-data>
   timestamp:       n (16 bytes)
   type:			n (1 byte)
        open		0
        close		1
        exec		8
        bind-text	16
        bind-double	17
        bind-int	18
        bind-null	19
        bind-value	20
        bind-clear	21
        prep		32
        step		33
        reset		34
        finalize	35

  open-arg-data:		<connection><path><flags>
  close-arg-data:		<connection>
  exec-arg-data:		<connection><len><statement-text>
  bind-text-arg-data:	<statement-ref><index><len><data>
  bind-double-arg-data:	<statement-ref><index><data>
  bind-int-arg-data:	<statement-ref><index><data>
  bind-null-arg-data:	<statement-ref><index>
  bind-value-arg-data:	<statement-ref><index><len><data> ???
  bind-clear-arg-data:	<statement-ref>
  prep-arg-data:		<connection><len><statement-text>
  step-arg-data:		<statement-ref>
  reset-arg-data:		<statement-ref>
  finalize-arg-data:	<statement-ref>

NOTES

Added ext/sqlrr/sqlrr.c.











































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
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
411
412
413
414
415
416
417
418
419
420
421
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
524
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
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
/*
 *  sqlrr.c
 */

#include "sqlrr.h"

#if defined(SQLITE_ENABLE_SQLRR)

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/param.h>
#include <errno.h>
#include <pthread.h>
#include <libkern/OSAtomic.h>

#include "sqliteInt.h"
#include "vdbeInt.h"

#define LOGSUFFIXLEN 48

/* 
 * Data types 
 */
typedef struct SRRLogRef SRRLogRef;
struct SRRLogRef {
    int fd;
    sqlite3 *db;
    const char *dbPath;
    char *logPath;
    int connection;
    int depth;
    SRRLogRef *nextRef;
};

/* 
 * Globals 
 */
SRRLogRef *logRefHead = NULL;
int dbLogCount = 0;
static int srr_enabled = 1;
pthread_mutex_t srr_log_mutex;
static volatile int32_t srr_initialized = 0;

/* 
 * Log management 
 */
extern void SRRecInitialize() {
    int go = OSAtomicCompareAndSwap32Barrier(0, 1, &srr_initialized); 
    if( go ){
        pthread_mutex_init(&srr_log_mutex, NULL);
    }
}

static SRRLogRef *createLog(sqlite3 *db, const char *dbPath) {
    SRRLogRef *ref = NULL;
    char *baseDir = getenv("SQLITE_REPLAY_RECORD_DIR");
    char logPath[MAXPATHLEN] = "";
    char suffix[LOGSUFFIXLEN] = "";
    const char *dbName = dbPath;
    int len = 0;
    int index = 0;
    int fd = -1;
    size_t out;
    unsigned char version = SRR_FILE_VERSION;
    
    SRRecInitialize();

    /* construct the path for the log file 
     * ${SQLITE_REPLAY_DIR}/<dbname>_<pid>_<connection_number>.sqlrr
     */
    if (baseDir == NULL) {
        baseDir = "/tmp"; /* getenv(TMPDIR) */
    }
    len = strlen(baseDir);
    strlcat(logPath, baseDir, MAXPATHLEN);
    if ((len>0) && (baseDir[len-1] != '/')) {
        strlcat(logPath, "/", MAXPATHLEN);
    }
    len = strlen(dbPath);
    for (index = len-2; index >= 0; index --){
        if (dbPath[index] == '/') {
            dbName = &dbPath[index+1];
            break;
        }
    }
    strlcat(logPath, dbName, MAXPATHLEN);
    int cNum = ++dbLogCount;
    snprintf(suffix, sizeof(suffix), "_%d_%d_XXXX.sqlrr", getpid(), cNum);
    len = strlcat(logPath, suffix, MAXPATHLEN);
    /* make it unique if we have the space */
    if ((len + 1) < MAXPATHLEN) {
        fd = mkstemps(logPath, 6);
    } else {
        fprintf(stderr, "Failed to create sqlite replay log path for %s [%s]\n", dbPath, logPath);
        return NULL;
    }
    if (fd == -1) {
        fprintf(stderr, "Failed to create sqlite replay log file for %s with path %s [%s]\n", dbPath, logPath, strerror(errno));
        return NULL;
    }
    fprintf(stdout, "Writing sqlite replay log file %s\n", logPath);
    out = write(fd, SRR_FILE_SIGNATURE, SRR_FILE_SIGNATURE_LEN);
    if (out!=-1) {
        out = write(fd, &version, 1);
    }
    if (out == -1){
        fprintf(stderr, "Write failure on log [%s]: %s\n", logPath, strerror(errno));
        close(fd);
        return NULL;
    }

    len = strlen(logPath) + 1;
    ref = (SRRLogRef *)malloc(sizeof(SRRLogRef));

    ref->db = db;
    ref->dbPath = dbPath;
    ref->logPath = (char *)malloc(len * sizeof(char));
    strlcpy(ref->logPath, logPath, len);
    ref->fd = fd;
    ref->connection = cNum;
    ref->depth = 0;
    
    pthread_mutex_lock(&srr_log_mutex);
    ref->nextRef = logRefHead;
    logRefHead = ref;
    pthread_mutex_unlock(&srr_log_mutex);
    return ref;
}

static void closeLog(sqlite3 *db) {
    SRRLogRef *ref = NULL;
    SRRLogRef *lastRef = NULL;

    pthread_mutex_lock(&srr_log_mutex);
    for (ref = logRefHead; ref != NULL; ref = ref->nextRef) {
        if (ref->db == db) {
            if (lastRef == NULL) {
                logRefHead = ref->nextRef;
            } else {
                lastRef->nextRef = ref->nextRef;
            }
        }
    }
    pthread_mutex_unlock(&srr_log_mutex);

    if (ref != NULL) {
        fprintf(stdout, "Closing sqlite replay log file %s\n", ref->logPath);
        close(ref->fd);
        free(ref->logPath);
        free(ref);
    }
}

static SRRLogRef *getLog(sqlite3 *db) {
    pthread_mutex_lock(&srr_log_mutex);
    SRRLogRef *ref = logRefHead;
    for (ref = logRefHead; ref != NULL; ref = ref->nextRef) {
        if (ref->db == db) {
            pthread_mutex_unlock(&srr_log_mutex);
            return ref;
        }
    }
    pthread_mutex_unlock(&srr_log_mutex);
    return NULL;
}


/*
 * SQLite recording API
 */
void SQLiteReplayRecorder(int flag) {
    srr_enabled = flag;
}

// open-arg-data:		<connection><len><path><flags>
void _SRRecOpen(sqlite3 *db, const char *path, int flags) {
    if (!srr_enabled) return;
    if (db) {
        SRRLogRef *ref = createLog(db, path);
        if (ref) {
            SRRCommand code = SRROpen;
            int len = strlen(path);
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out=write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { out=write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
            if (out!=-1) { out=write(ref->fd, &len, sizeof(len)); }
            if (out!=-1) { out=write(ref->fd, path, len); }
            if (out!=-1) { out=write(ref->fd, &flags, sizeof(flags)); }
            if (out==-1) {
                fprintf(stderr, "Error writing open to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(db);
            }
        }
    }
}

//close-arg-data:		<connection>
void SRRecClose(sqlite3 *db) {
    if (!srr_enabled) return;
    if (db) {
        SRRLogRef *ref = getLog(db);
        if (ref) {
            SRRCommand code = SRRClose;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { out = write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
            if (out==-1) {
                fprintf(stderr, "Error writing close to log file [%s]: %s\n", ref->logPath, strerror(errno));
            }
            closeLog(db);
        }
    }
}

// exec-arg-data:		<connection><len><statement-text>
void SRRecExec(sqlite3 *db, const char *sql) {
    if (!srr_enabled) return;
    if (db) {
        SRRLogRef *ref = getLog(db);
        if (ref) {
            if (ref->depth == 0) {
                SRRCommand code = SRRExec;
                int len = strlen(sql);
                struct timeval tv;
                size_t out;
                
                ref->depth = 1;
                gettimeofday(&tv, NULL);
                out = write(ref->fd, &tv, sizeof(tv));
                if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
                if (out!=-1) { out = write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
                if (out!=-1) { out = write(ref->fd, &len, sizeof(len)); }
                if (out!=-1) { out = write(ref->fd, sql, len); }
                if (out==-1) {
                    fprintf(stderr, "Error writing exec to log file [%s]: %s\n", ref->logPath, strerror(errno));
                    closeLog(db);
                }
            } else {
                ref->depth ++;
            }
        }
    }
}

void SRRecExecEnd(sqlite3 *db) {
    if (!srr_enabled) return;
    if (db) {
        SRRLogRef *ref = getLog(db);
        if (ref) {
            ref->depth --;
        }
    }
}
            
// prep-arg-data:		<connection><len><statement-text><savesql><statement-ref>
void _SRRecPrepare(sqlite3 *db, const char *sql, int nBytes, int saveSql, sqlite3_stmt *pStmt) {
    if (!srr_enabled) return;
    if ((db!=NULL)&&(pStmt!=NULL)) {
        SRRLogRef *ref = getLog(db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRPrepare;
            struct timeval tv;
            size_t out;
            int sqlLen = nBytes;

            if (sqlLen == -1) {
                sqlLen = strlen(sql);
            }
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { out = write(ref->fd, &(ref->connection), sizeof(ref->connection)); }
            if (out!=-1) { out = write(ref->fd, &sqlLen, sizeof(sqlLen)); }
            if (out!=-1) { out = write(ref->fd, sql, sqlLen); }
            if (out!=-1) { out = write(ref->fd, &saveSql, sizeof(saveSql)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out==-1) {
                fprintf(stderr, "Error writing prepare to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(db);
            }
        }
    }
}

//step-arg-data:		<statement-ref>
void SRRecStep(sqlite3_stmt *pStmt) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref) {
            if (ref->depth == 0) {
                SRRCommand code = SRRStep;
                struct timeval tv;
                size_t out;
                
                ref->depth = 1;
                gettimeofday(&tv, NULL);
                out = write(ref->fd, &tv, sizeof(tv));
                if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
                if (out!=-1) { 
                    int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                    out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
                }
                if (out==-1) {
                    fprintf(stderr, "Error writing step to log file [%s]: %s\n", ref->logPath, strerror(errno));
                    closeLog(ref->db);
                }
            } else {
                ref->depth ++;
            }            
        }
    }
}

void SRRecStepEnd(sqlite3_stmt *pStmt) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref) {
            ref->depth --;
        }
    }
}

// reset-arg-data:		<statement-ref>
void SRRecReset(sqlite3_stmt *pStmt) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRReset;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out==-1) {
                fprintf(stderr, "Error writing reset to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

// finalize-arg-data:	<statement-ref>
void SRRecFinalize(sqlite3_stmt *pStmt) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRFinalize;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out==-1) {
                fprintf(stderr, "Error writing finalize to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

// bind-text-arg-data:	<statement-ref><index><len><data>
void SRRecBindText(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRBindText;
            struct timeval tv;
            size_t out;
            int64_t textLen = nData;
            if (textLen == -1) {
                textLen = strlen(zData);
            }
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
            if (out!=-1) { out = write(ref->fd, &textLen, sizeof(textLen)); }
            if (out!=-1) { out = write(ref->fd, zData, textLen); }
            if (out==-1) {
                fprintf(stderr, "Error writing bind text to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

// bind-blob-arg-data:	<statement-ref><index><len>[<data>]
void SRRecBindBlob(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRBindBlob;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
            if (zData == NULL) {
                int64_t negNData = -nData;
                if (out!=-1) { out = write(ref->fd, &negNData, sizeof(negNData)); }
            } else {
                if (out!=-1) { out = write(ref->fd, &nData, sizeof(nData)); }
                if (out!=-1) { out = write(ref->fd, zData, nData); }
            }
            if (out==-1) {
                fprintf(stderr, "Error writing bind blob to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

// bind-double-arg-data:	<statement-ref><index><data>
void SRRecBindDouble(sqlite3_stmt *pStmt, int i, double value) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRBindDouble;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
            if (out!=-1) { out = write(ref->fd, &value, sizeof(value)); }
            if (out==-1) {
                fprintf(stderr, "Error writing bind double to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

// bind-int-arg-data:	<statement-ref><index><data>
void SRRecBindInt64(sqlite3_stmt *pStmt, int i, int64_t value) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRBindInt;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
            if (out!=-1) { out = write(ref->fd, &value, sizeof(value)); }
            if (out==-1) {
                fprintf(stderr, "Error writing bind int to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

// bind-null-arg-data:	<statement-ref><index>
void SRRecBindNull(sqlite3_stmt *pStmt, int i) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRBindNull;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out!=-1) { out = write(ref->fd, &i, sizeof(i)); }
            if (out==-1) {
                fprintf(stderr, "Error writing bind null to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

// bind-value-arg-data:	<statement-ref><index><len><data> ???
void SRRecBindValue(sqlite3_stmt *pStmt, int i, const sqlite3_value *value) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            fprintf(stderr, "SRRecBindValue(sqlite3_bind_value) is not yet supported, closing [%s]: %s\n", ref->logPath, strerror(errno));
            closeLog(ref->db);
        }
    }
}

// bind-clear-arg-data:	<statement-ref>
void SRRecClearBindings(sqlite3_stmt *pStmt) {
    if (!srr_enabled) return;
    if(pStmt!=NULL) {
        Vdbe *v = (Vdbe *)pStmt;
        SRRLogRef *ref = getLog(v->db);
        if (ref && (ref->depth == 0)) {
            SRRCommand code = SRRBindClear;
            struct timeval tv;
            size_t out;
            
            gettimeofday(&tv, NULL);
            out = write(ref->fd, &tv, sizeof(tv));
            if (out!=-1) { out = write(ref->fd, &code, sizeof(SRRCommand)); }
            if (out!=-1) { 
                int64_t stmtInt = (int64_t)((intptr_t)(pStmt));
                out = write(ref->fd, &stmtInt, sizeof(int64_t)); 
            }
            if (out==-1) {
                fprintf(stderr, "Error writing clear bindings to log file [%s]: %s\n", ref->logPath, strerror(errno));
                closeLog(ref->db);
            }
        }
    }
}

#endif /* SQLITE_ENABLE_SQLRR */

Added ext/sqlrr/sqlrr.h.



























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
 *  sqlrr.h
 */

#ifndef _SQLRR_H_
#define _SQLRR_H_

/*
** Header constants
*/
#define SRR_FILE_SIGNATURE       "SQLRR"
#define SRR_FILE_SIGNATURE_LEN   5
#define SRR_FILE_VERSION         0x1 
#define SRR_FILE_VERSION_LEN     1

#if defined(SQLITE_ENABLE_SQLRR)

#include "sqlite3.h"
#include <sys/types.h>

#define SRRecOpen(A,B,C)        if(!rc){_SRRecOpen(A,B,C);}
#define SRRecPrepare(A,B,C,D,E) if(!rc){_SRRecPrepare(A,B,C,D,E);}

typedef enum {
    SRROpen = 0,
    SRRClose = 1,
    SRRExec = 8,
    SRRBindText = 16,
    SRRBindBlob = 17,
    SRRBindDouble = 18,
    SRRBindInt = 19,
    SRRBindNull = 20,
    SRRBindValue = 21,
    SRRBindClear = 22,
    SRRPrepare = 32,
    SRRStep = 33,
    SRRReset = 34,
    SRRFinalize = 35
} SRRCommand;

extern void SQLiteReplayRecorder(int flag);
extern void _SRRecOpen(sqlite3 *db, const char *path, int flags);
extern void SRRecClose(sqlite3 *db);
extern void SRRecExec(sqlite3 *db, const char *sql);
extern void SRRecExecEnd(sqlite3 *db);
extern void _SRRecPrepare(sqlite3 *db, const char *sql, int nBytes, int saveSql, sqlite3_stmt *stmt);
extern void SRRecStep(sqlite3_stmt *pStmt);
extern void SRRecStepEnd(sqlite3_stmt *pStmt);
extern void SRRecReset(sqlite3_stmt *pStmt);
extern void SRRecFinalize(sqlite3_stmt *pStmt);
extern void SRRecBindText(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData);
extern void SRRecBindBlob(sqlite3_stmt *pStmt, int i, const char *zData, int64_t nData);
extern void SRRecBindDouble(sqlite3_stmt *pStmt, int i, double value);
extern void SRRecBindInt64(sqlite3_stmt *pStmt, int i, int64_t value);
extern void SRRecBindNull(sqlite3_stmt *pStmt, int i);
extern void SRRecBindValue(sqlite3_stmt *pStmt, int i, const sqlite3_value *value);
extern void SRRecClearBindings(sqlite3_stmt *pStmt);

#endif /* defined(SQLITE_ENABLE_SQLRR) */

#endif /* _SQLRR_H_ */

Changes to main.mk.

227
228
229
230
231
232
233



234
235
236
237
238
239
240
...
474
475
476
477
478
479
480


481
482
483
484
485
486
487
...
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
  $(TOP)/ext/icu/sqliteicu.h \
  $(TOP)/ext/icu/icu.c
SRC += \
  $(TOP)/ext/rtree/sqlite3rtree.h \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/rtree.c \
  $(TOP)/ext/rtree/geopoly.c



SRC += \
  $(TOP)/ext/session/sqlite3session.c \
  $(TOP)/ext/session/sqlite3session.h
SRC += \
  $(TOP)/ext/userauth/userauth.c \
  $(TOP)/ext/userauth/sqlite3userauth.h
SRC += \
................................................................................
  $(TOP)/ext/fts2/fts2_hash.h \
  $(TOP)/ext/fts2/fts2_tokenizer.h
EXTHDR += \
  $(TOP)/ext/fts3/fts3.h \
  $(TOP)/ext/fts3/fts3Int.h \
  $(TOP)/ext/fts3/fts3_hash.h \
  $(TOP)/ext/fts3/fts3_tokenizer.h


EXTHDR += \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/geopoly.c
EXTHDR += \
  $(TOP)/ext/icu/sqliteicu.h
EXTHDR += \
  $(TOP)/ext/fts5/fts5Int.h  \
................................................................................

# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
target_source:	$(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c
	rm -rf tsrc
	mkdir tsrc
	cp -f $(SRC) tsrc
	rm tsrc/sqlite.h.in tsrc/parse.y
	tclsh $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
	mv vdbe.new tsrc/vdbe.c
	cp fts5.c fts5.h tsrc
	touch target_source

sqlite3.c:	target_source $(TOP)/tool/mksqlite3c.tcl







>
>
>







 







>
>







 







|


|







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  $(TOP)/ext/icu/sqliteicu.h \
  $(TOP)/ext/icu/icu.c
SRC += \
  $(TOP)/ext/rtree/sqlite3rtree.h \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/rtree.c \
  $(TOP)/ext/rtree/geopoly.c
SRC += \
  $(TOP)/ext/sqlrr/sqlrr.h \
  $(TOP)/ext/sqlrr/sqlrr.c
SRC += \
  $(TOP)/ext/session/sqlite3session.c \
  $(TOP)/ext/session/sqlite3session.h
SRC += \
  $(TOP)/ext/userauth/userauth.c \
  $(TOP)/ext/userauth/sqlite3userauth.h
SRC += \
................................................................................
  $(TOP)/ext/fts2/fts2_hash.h \
  $(TOP)/ext/fts2/fts2_tokenizer.h
EXTHDR += \
  $(TOP)/ext/fts3/fts3.h \
  $(TOP)/ext/fts3/fts3Int.h \
  $(TOP)/ext/fts3/fts3_hash.h \
  $(TOP)/ext/fts3/fts3_tokenizer.h
EXTHDR += \
  $(TOP)/ext/sqlrr/sqlrr.h
EXTHDR += \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/geopoly.c
EXTHDR += \
  $(TOP)/ext/icu/sqliteicu.h
EXTHDR += \
  $(TOP)/ext/fts5/fts5Int.h  \
................................................................................

# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
target_source:	$(SRC) $(EXTHDR) $(TOP)/tool/vdbe-compress.tcl fts5.c
	rm -rf tsrc
	mkdir tsrc
	cp -f $(SRC) $(EXTHDR) tsrc
	rm tsrc/sqlite.h.in tsrc/parse.y
	tclsh $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
	mv vdbe.new tsrc/vdbe.c
	cp fts5.c fts5.h tsrc
	touch target_source

sqlite3.c:	target_source $(TOP)/tool/mksqlite3c.tcl

Changes to src/btree.c.

83
84
85
86
87
88
89





90
91

92
93
94
95
96
97
98
** Enable or disable the shared pager and schema features.
**
** This routine has no effect on existing database connections.
** The shared cache setting effects only future calls to
** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
int sqlite3_enable_shared_cache(int enable){





  sqlite3GlobalConfig.sharedCacheEnabled = enable;
  return SQLITE_OK;

}
#endif



#ifdef SQLITE_OMIT_SHARED_CACHE
  /*







>
>
>
>
>


>







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
** Enable or disable the shared pager and schema features.
**
** This routine has no effect on existing database connections.
** The shared cache setting effects only future calls to
** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
int sqlite3_enable_shared_cache(int enable){
#if defined(__APPLE__) && !defined(SQLITE_TEST) && !defined(TH3_COMPATIBILITY)
  /* Enable global shared cache function for debugging and unit tests, 
  ** but not for release */
  return SQLITE_MISUSE;
#else
  sqlite3GlobalConfig.sharedCacheEnabled = enable;
  return SQLITE_OK;
#endif
}
#endif



#ifdef SQLITE_OMIT_SHARED_CACHE
  /*

Changes to src/btreeInt.h.

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
#define MX_CELL(pBt) ((pBt->pageSize-8)/6)

/* Forward declarations */
typedef struct MemPage MemPage;
typedef struct BtLock BtLock;
typedef struct CellInfo CellInfo;

/*
** This is a magic string that appears at the beginning of every
** SQLite database in order to identify the file as a real database.
**
** You can change this value at compile-time by specifying a
** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
** header must be exactly 16 bytes including the zero-terminator so
** the string itself should be 15 characters long.  If you change
** the header, then your custom library will not be able to read 
** databases generated by the standard tools and the standard tools
** will not be able to read databases created by your custom library.
*/
#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
#  define SQLITE_FILE_HEADER "SQLite format 3"
#endif

/*
** Page type flags.  An ORed combination of these flags appear as the
** first byte of on-disk image of every BTree page.
*/
#define PTF_INTKEY    0x01
#define PTF_ZERODATA  0x02
#define PTF_LEAFDATA  0x04







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







229
230
231
232
233
234
235
















236
237
238
239
240
241
242
#define MX_CELL(pBt) ((pBt->pageSize-8)/6)

/* Forward declarations */
typedef struct MemPage MemPage;
typedef struct BtLock BtLock;
typedef struct CellInfo CellInfo;

















/*
** Page type flags.  An ORed combination of these flags appear as the
** first byte of on-disk image of every BTree page.
*/
#define PTF_INTKEY    0x01
#define PTF_ZERODATA  0x02
#define PTF_LEAFDATA  0x04

Changes to src/legacy.c.

12
13
14
15
16
17
18



19
20
21
22
23
24
25
..
38
39
40
41
42
43
44
45


46
47
48
49
50
51
52
...
119
120
121
122
123
124
125



126
127
128
129
130
131
132
** 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.
*/

#include "sqliteInt.h"




/*
** Execute SQL code.  Return one of the SQLITE_ success/failure
** codes.  Also write an error message into memory obtained from
** malloc() and make *pzErrMsg point to that message.
**
** If the SQL is a query, then for each row in the query result
................................................................................
  const char *zLeftover;      /* Tail of unprocessed SQL */
  sqlite3_stmt *pStmt = 0;    /* The current SQL statement */
  char **azCols = 0;          /* Names of result columns */
  int callbackIsInit;         /* True if callback data is initialized */

  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
  if( zSql==0 ) zSql = "";



  sqlite3_mutex_enter(db->mutex);
  sqlite3Error(db, SQLITE_OK);
  while( rc==SQLITE_OK && zSql[0] ){
    int nCol = 0;
    char **azVals = 0;

    pStmt = 0;
................................................................................
    sqlite3DbFree(db, azCols);
    azCols = 0;
  }

exec_out:
  if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt);
  sqlite3DbFree(db, azCols);




  rc = sqlite3ApiExit(db, rc);
  if( rc!=SQLITE_OK && pzErrMsg ){
    *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db));
    if( *pzErrMsg==0 ){
      rc = SQLITE_NOMEM_BKPT;
      sqlite3Error(db, SQLITE_NOMEM);







>
>
>







 







|
>
>







 







>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
..
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
** 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.
*/

#include "sqliteInt.h"
#ifdef SQLITE_ENABLE_SQLRR
# include "sqlrr.h"
#endif

/*
** Execute SQL code.  Return one of the SQLITE_ success/failure
** codes.  Also write an error message into memory obtained from
** malloc() and make *pzErrMsg point to that message.
**
** If the SQL is a query, then for each row in the query result
................................................................................
  const char *zLeftover;      /* Tail of unprocessed SQL */
  sqlite3_stmt *pStmt = 0;    /* The current SQL statement */
  char **azCols = 0;          /* Names of result columns */
  int callbackIsInit;         /* True if callback data is initialized */

  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
  if( zSql==0 ) zSql = "";
#ifdef SQLITE_ENABLE_SQLRR
  SRRecExec(db, zSql);
#endif  
  sqlite3_mutex_enter(db->mutex);
  sqlite3Error(db, SQLITE_OK);
  while( rc==SQLITE_OK && zSql[0] ){
    int nCol = 0;
    char **azVals = 0;

    pStmt = 0;
................................................................................
    sqlite3DbFree(db, azCols);
    azCols = 0;
  }

exec_out:
  if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt);
  sqlite3DbFree(db, azCols);
#ifdef SQLITE_ENABLE_SQLRR
  SRRecExecEnd(db);
#endif

  rc = sqlite3ApiExit(db, rc);
  if( rc!=SQLITE_OK && pzErrMsg ){
    *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db));
    if( *pzErrMsg==0 ){
      rc = SQLITE_NOMEM_BKPT;
      sqlite3Error(db, SQLITE_NOMEM);

Changes to src/main.c.

12
13
14
15
16
17
18



19
20
21
22
23
24
25
....
1301
1302
1303
1304
1305
1306
1307




1308
1309
1310
1311
1312
1313
1314
....
1413
1414
1415
1416
1417
1418
1419

1420
1421
1422
1423
1424
1425
1426
....
2730
2731
2732
2733
2734
2735
2736






































2737
2738
2739
2740
2741
2742
2743
....
2984
2985
2986
2987
2988
2989
2990



































































2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003


3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
....
3394
3395
3396
3397
3398
3399
3400




















3401



3402
3403
3404
3405
3406
3407
3408
....
3838
3839
3840
3841
3842
3843
3844








3845
3846
3847
3848
3849
3850
3851
3852

3853
3854
3855
3856
3857
3858
3859
....
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
....
4389
4390
4391
4392
4393
4394
4395


























4396
4397
4398
4399
4400
4401
4402
** 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.
*/
#include "sqliteInt.h"




#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
#ifdef SQLITE_ENABLE_RTREE
# include "rtree.h"
#endif
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
................................................................................
  sqlite3_mutex_leave(db->mutex);
  db->magic = SQLITE_MAGIC_CLOSED;
  sqlite3_mutex_free(db->mutex);
  assert( sqlite3LookasideUsed(db,0)==0 );
  if( db->lookaside.bMalloced ){
    sqlite3_free(db->lookaside.pStart);
  }




  sqlite3_free(db);
}

/*
** Rollback all database files.  If tripCode is not SQLITE_OK, then
** any write cursors are invalidated ("tripped" - as in "tripping a circuit
** breaker") and made to return tripCode if there are any further
................................................................................
      case SQLITE_IOERR_SHMLOCK:      zName = "SQLITE_IOERR_SHMLOCK";     break;
      case SQLITE_IOERR_SHMMAP:       zName = "SQLITE_IOERR_SHMMAP";      break;
      case SQLITE_IOERR_SEEK:         zName = "SQLITE_IOERR_SEEK";        break;
      case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break;
      case SQLITE_IOERR_MMAP:         zName = "SQLITE_IOERR_MMAP";        break;
      case SQLITE_IOERR_GETTEMPPATH:  zName = "SQLITE_IOERR_GETTEMPPATH"; break;
      case SQLITE_IOERR_CONVPATH:     zName = "SQLITE_IOERR_CONVPATH";    break;

      case SQLITE_CORRUPT:            zName = "SQLITE_CORRUPT";           break;
      case SQLITE_CORRUPT_VTAB:       zName = "SQLITE_CORRUPT_VTAB";      break;
      case SQLITE_NOTFOUND:           zName = "SQLITE_NOTFOUND";          break;
      case SQLITE_FULL:               zName = "SQLITE_FULL";              break;
      case SQLITE_CANTOPEN:           zName = "SQLITE_CANTOPEN";          break;
      case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break;
      case SQLITE_CANTOPEN_ISDIR:     zName = "SQLITE_CANTOPEN_ISDIR";    break;
................................................................................
    if( newLimit>aHardLimit[limitId] ){
      newLimit = aHardLimit[limitId];  /* IMP: R-51463-25634 */
    }
    db->aLimit[limitId] = newLimit;
  }
  return oldLimit;                     /* IMP: R-53341-35419 */
}







































/*
** This function is used to parse both URIs and non-URI filenames passed by the
** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database
** URIs specified as part of ATTACH statements.
**
** The first argument to this function is the name of the VFS to use (or
................................................................................
    sqlite3_free(zFile);
    zFile = 0;
  }
  *pFlags = flags;
  *pzFile = zFile;
  return rc;
}




































































#if defined(SQLITE_HAS_CODEC)
/*
** Process URI filename query parameters relevant to the SQLite Encryption
** Extension.  Return true if any of the relevant query parameters are
** seen and return false if not.
*/
int sqlite3CodecQueryParameters(
  sqlite3 *db,           /* Database connection */
  const char *zDb,       /* Which schema is being created/attached */
  const char *zUri       /* URI filename */
){
  const char *zKey;


  if( (zKey = sqlite3_uri_parameter(zUri, "hexkey"))!=0 && zKey[0] ){
    u8 iByte;
    int i;
    char zDecoded[40];
    for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
      iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
      if( (i&1)!=0 ) zDecoded[i/2] = iByte;
    }
    sqlite3_key_v2(db, zDb, zDecoded, i/2);
    return 1;
  }else if( (zKey = sqlite3_uri_parameter(zUri, "key"))!=0 ){
    sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey));
    return 1;
  }else if( (zKey = sqlite3_uri_parameter(zUri, "textkey"))!=0 ){
    sqlite3_key_v2(db, zDb, zKey, -1);
    return 1;
  }else{
    return 0;
  }
}
#endif


/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
** is UTF-8 encoded.
*/
static int openDatabase(
................................................................................
  assert( db!=0 || rc==SQLITE_NOMEM );
  if( rc==SQLITE_NOMEM ){
    sqlite3_close(db);
    db = 0;
  }else if( rc!=SQLITE_OK ){
    db->magic = SQLITE_MAGIC_SICK;
  }




















  *ppDb = db;



#ifdef SQLITE_ENABLE_SQLLOG
  if( sqlite3GlobalConfig.xSqllog ){
    /* Opening a db handle. Fourth parameter is passed 0. */
    void *pArg = sqlite3GlobalConfig.pSqllogArg;
    sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
  }
#endif
................................................................................
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_VFS_POINTER ){
      *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
      *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
      rc = SQLITE_OK;








    }else if( op==SQLITE_FCNTL_DATA_VERSION ){
      *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
      rc = SQLITE_OK;
    }else{
      rc = sqlite3OsFileControl(fd, op, pArg);
    }
    sqlite3BtreeLeave(pBtree);
  }

  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Interface to the testing logic.
*/
................................................................................
** query parameter we seek.  This routine returns the value of the zParam
** parameter if it exists.  If the parameter does not exist, this routine
** returns a NULL pointer.
*/
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
  if( zFilename==0 || zParam==0 ) return 0;
  zFilename = databaseName(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] ){
    int x = strcmp(zFilename, zParam);
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}

/*
** Return a pointer to the name of Nth query parameter of the filename.
*/
const char *sqlite3_uri_key(const char *zFilename, int N){
  if( zFilename==0 || N<0 ) return 0;
................................................................................
    (void)SQLITE_MISUSE_BKPT;
    return -1;
  }
#endif
  pBt = sqlite3DbNameToBtree(db, zDbName);
  return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
}



























#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** Obtain a snapshot handle for the snapshot of database zDb currently 
** being read by handle db.
*/
int sqlite3_snapshot_get(







>
>
>







 







>
>
>
>







 







>







 







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







 







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













>
>
|









|


|







<







 







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

>
>
>







 







>
>
>
>
>
>
>
>








>







 







<
<
|
<
<
<
<
<







 







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







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
....
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
....
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
....
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139

3140
3141
3142
3143
3144
3145
3146
....
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
....
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
....
4414
4415
4416
4417
4418
4419
4420


4421





4422
4423
4424
4425
4426
4427
4428
....
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
** 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.
*/
#include "sqliteInt.h"

#ifdef SQLITE_ENABLE_SQLRR
# include "sqlrr.h"
#endif 
#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
#ifdef SQLITE_ENABLE_RTREE
# include "rtree.h"
#endif
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
................................................................................
  sqlite3_mutex_leave(db->mutex);
  db->magic = SQLITE_MAGIC_CLOSED;
  sqlite3_mutex_free(db->mutex);
  assert( sqlite3LookasideUsed(db,0)==0 );
  if( db->lookaside.bMalloced ){
    sqlite3_free(db->lookaside.pStart);
  }
#ifdef SQLITE_ENABLE_SQLRR
  SRRecClose(db);
#endif
  
  sqlite3_free(db);
}

/*
** Rollback all database files.  If tripCode is not SQLITE_OK, then
** any write cursors are invalidated ("tripped" - as in "tripping a circuit
** breaker") and made to return tripCode if there are any further
................................................................................
      case SQLITE_IOERR_SHMLOCK:      zName = "SQLITE_IOERR_SHMLOCK";     break;
      case SQLITE_IOERR_SHMMAP:       zName = "SQLITE_IOERR_SHMMAP";      break;
      case SQLITE_IOERR_SEEK:         zName = "SQLITE_IOERR_SEEK";        break;
      case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break;
      case SQLITE_IOERR_MMAP:         zName = "SQLITE_IOERR_MMAP";        break;
      case SQLITE_IOERR_GETTEMPPATH:  zName = "SQLITE_IOERR_GETTEMPPATH"; break;
      case SQLITE_IOERR_CONVPATH:     zName = "SQLITE_IOERR_CONVPATH";    break;
      case SQLITE_IOERR_VNODE:        zName = "SQLITE_IOERR_VNODE";       break;
      case SQLITE_CORRUPT:            zName = "SQLITE_CORRUPT";           break;
      case SQLITE_CORRUPT_VTAB:       zName = "SQLITE_CORRUPT_VTAB";      break;
      case SQLITE_NOTFOUND:           zName = "SQLITE_NOTFOUND";          break;
      case SQLITE_FULL:               zName = "SQLITE_FULL";              break;
      case SQLITE_CANTOPEN:           zName = "SQLITE_CANTOPEN";          break;
      case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break;
      case SQLITE_CANTOPEN_ISDIR:     zName = "SQLITE_CANTOPEN_ISDIR";    break;
................................................................................
    if( newLimit>aHardLimit[limitId] ){
      newLimit = aHardLimit[limitId];  /* IMP: R-51463-25634 */
    }
    db->aLimit[limitId] = newLimit;
  }
  return oldLimit;                     /* IMP: R-53341-35419 */
}
#if defined(SQLITE_ENABLE_AUTO_PROFILE)
/* stderr logging */
void _sqlite_auto_profile(void *aux, const char *sql, u64 ns);
void _sqlite_auto_trace(void *aux, const char *sql);
void _sqlite_auto_profile(void *aux, const char *sql, u64 ns) {
#pragma unused(aux)
	fprintf(stderr, "Query: %s\n Execution Time: %llu ms\n", sql, ns / 1000000);
}
void _sqlite_auto_trace(void *aux, const char *sql) {
	fprintf(stderr, "TraceSQL(%p): %s\n", aux, sql);
}

/* syslog logging */
#include <asl.h>
static aslclient autolog_client = NULL;
static void _close_asl_log() {
  if( NULL!=autolog_client ){
    asl_close(autolog_client);
    autolog_client = NULL;
  }
}
static void _open_asl_log() {
  if( NULL==autolog_client ){
    autolog_client = asl_open("SQLite", NULL, 0);
    atexit(_close_asl_log);
  }
}

void _sqlite_auto_profile_syslog(void *aux, const char *sql, u64 ns);
void _sqlite_auto_trace_syslog(void *aux, const char *sql);
void _sqlite_auto_profile_syslog(void *aux, const char *sql, u64 ns) {
#pragma unused(aux)
	asl_log(autolog_client, NULL, ASL_LEVEL_NOTICE, "Query: %s\n Execution Time: %llu ms\n", sql, ns / 1000000);
}
void _sqlite_auto_trace_syslog(void *aux, const char *sql) {
	asl_log(autolog_client, NULL, ASL_LEVEL_NOTICE, "TraceSQL(%p): %s\n", aux, sql);
}
#endif

/*
** This function is used to parse both URIs and non-URI filenames passed by the
** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database
** URIs specified as part of ATTACH statements.
**
** The first argument to this function is the name of the VFS to use (or
................................................................................
    sqlite3_free(zFile);
    zFile = 0;
  }
  *pFlags = flags;
  *pzFile = zFile;
  return rc;
}

#if defined(SQLITE_ENABLE_AUTO_PROFILE)
#define SQLITE_AUTOLOGGING_STDERR 1
#define SQLITE_AUTOLOGGING_SYSLOG 2
static void enableAutoLogging(
  sqlite3 *db
){
  char *envprofile = getenv("SQLITE_AUTO_PROFILE");
  
  if( envprofile!=NULL ){
    int where = 0;
    if( !strncasecmp("1", envprofile, 1) ){
      if( isatty(2) ){
        where = SQLITE_AUTOLOGGING_STDERR;
      }else{
        where = SQLITE_AUTOLOGGING_SYSLOG;
      }
    } else if( !strncasecmp("stderr", envprofile, 6) ){
      where = SQLITE_AUTOLOGGING_STDERR;
    } else if( !strncasecmp("syslog", envprofile, 6) ){
      where = SQLITE_AUTOLOGGING_SYSLOG;
    }
    if( where==SQLITE_AUTOLOGGING_STDERR ){
      sqlite3_profile(db, _sqlite_auto_profile, db);
    }else if( where==SQLITE_AUTOLOGGING_SYSLOG ){
      _open_asl_log();
      sqlite3_profile(db, _sqlite_auto_profile_syslog, db);
    }
  }
  char *envtrace = getenv("SQLITE_AUTO_TRACE");
  if( envtrace!=NULL ){
    int where = 0;
    if( !strncasecmp("1", envtrace, 1) ){
      if( isatty(2) ){
        where = SQLITE_AUTOLOGGING_STDERR;
      }else{
        where = SQLITE_AUTOLOGGING_SYSLOG;
      }
    } else if( !strncasecmp("stderr", envtrace, 6) ){
      where = SQLITE_AUTOLOGGING_STDERR;
    } else if( !strncasecmp("syslog", envtrace, 6) ){
      where = SQLITE_AUTOLOGGING_SYSLOG;
    }
    if( where==SQLITE_AUTOLOGGING_STDERR ){
      sqlite3_trace(db, _sqlite_auto_trace, db);
    }else if( where==SQLITE_AUTOLOGGING_SYSLOG ){
      _open_asl_log();
      sqlite3_trace(db, _sqlite_auto_trace_syslog, db);
    }
  }
}
#endif

/*
** This routine does the core work of extracting URI parameters from a
** database filename for the sqlite3_uri_parameter() interface.
*/
static const char *uriParameter(const char *zFilename, const char *zParam){
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] ){
    int x = strcmp(zFilename, zParam);
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}

#if defined(SQLITE_HAS_CODEC)
/*
** Process URI filename query parameters relevant to the SQLite Encryption
** Extension.  Return true if any of the relevant query parameters are
** seen and return false if not.
*/
int sqlite3CodecQueryParameters(
  sqlite3 *db,           /* Database connection */
  const char *zDb,       /* Which schema is being created/attached */
  const char *zUri       /* URI filename */
){
  const char *zKey;
  if( zUri==0 ){
    return 0;
  }else if( (zKey = uriParameter(zUri, "hexkey"))!=0 && zKey[0] ){
    u8 iByte;
    int i;
    char zDecoded[40];
    for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
      iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
      if( (i&1)!=0 ) zDecoded[i/2] = iByte;
    }
    sqlite3_key_v2(db, zDb, zDecoded, i/2);
    return 1;
  }else if( (zKey = uriParameter(zUri, "key"))!=0 ){
    sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey));
    return 1;
  }else if( (zKey = uriParameter(zUri, "textkey"))!=0 ){
    sqlite3_key_v2(db, zDb, zKey, -1);
    return 1;
  }else{
    return 0;
  }
}
#endif


/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
** is UTF-8 encoded.
*/
static int openDatabase(
................................................................................
  assert( db!=0 || rc==SQLITE_NOMEM );
  if( rc==SQLITE_NOMEM ){
    sqlite3_close(db);
    db = 0;
  }else if( rc!=SQLITE_OK ){
    db->magic = SQLITE_MAGIC_SICK;
  }
#if defined(__APPLE__) && ENABLE_FORCE_WAL
  if( db && !rc ){
    if ((0 == access("/var/db/enableForceWAL", R_OK))) {
#ifdef SQLITE_DEBUG
      fprintf(stderr, "SQLite WAL journal_mode ENABLED by default.\n");
#endif
      
      sqlite3_exec(db, "pragma journal_mode=wal", NULL, NULL, NULL);
#ifdef SQLITE_DEBUG
//    } else {
//      fprintf(stderr, "SQLite WAL journal_mode NOT ENABLED by default.\n");
#endif
    }
  }
#endif
#if defined(SQLITE_ENABLE_AUTO_PROFILE)
  if( db && !rc ){
    enableAutoLogging(db);
  }
#endif
  *ppDb = db;
#ifdef SQLITE_ENABLE_SQLRR
  SRRecOpen(db, zFilename, flags);
#endif
#ifdef SQLITE_ENABLE_SQLLOG
  if( sqlite3GlobalConfig.xSqllog ){
    /* Opening a db handle. Fourth parameter is passed 0. */
    void *pArg = sqlite3GlobalConfig.pSqllogArg;
    sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
  }
#endif
................................................................................
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_VFS_POINTER ){
      *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
      rc = SQLITE_OK;
    }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
      *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
      rc = SQLITE_OK;
#ifndef SQLITE_OMIT_WAL
      if( (rc==SQLITE_OK)&&(op==SQLITE_FCNTL_LAST_ERRNO)&&(*(int *)pArg==0) ){
        sqlite3_file *pWalFd = sqlite3PagerWalFile(pPager);
        if( pWalFd&&(pWalFd->pMethods) ){
          rc = sqlite3OsFileControl(pWalFd, op, pArg);
        }
      }
#endif
    }else if( op==SQLITE_FCNTL_DATA_VERSION ){
      *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
      rc = SQLITE_OK;
    }else{
      rc = sqlite3OsFileControl(fd, op, pArg);
    }
    sqlite3BtreeLeave(pBtree);
  }
  sqlite3Error(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Interface to the testing logic.
*/
................................................................................
** query parameter we seek.  This routine returns the value of the zParam
** parameter if it exists.  If the parameter does not exist, this routine
** returns a NULL pointer.
*/
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
  if( zFilename==0 || zParam==0 ) return 0;
  zFilename = databaseName(zFilename);


  return uriParameter(zFilename, zParam);





}

/*
** Return a pointer to the name of Nth query parameter of the filename.
*/
const char *sqlite3_uri_key(const char *zFilename, int N){
  if( zFilename==0 || N<0 ) return 0;
................................................................................
    (void)SQLITE_MISUSE_BKPT;
    return -1;
  }
#endif
  pBt = sqlite3DbNameToBtree(db, zDbName);
  return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
}
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)

#include "sqlite3_private.h"

/* 
** Testing a file path for sqlite locks held by a process ID. 
** Returns SQLITE_LOCKSTATE_ON if locks are present on path
** that would prevent writing to the database.
*/
int _sqlite3_lockstate(const char *path, pid_t pid){
  sqlite3 *db = NULL;
  
  if( sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK ){
    LockstatePID lockstate = {pid, -1};
    sqlite3_file_control(db, NULL, SQLITE_FCNTL_LOCKSTATE_PID, &lockstate);
    sqlite3_close(db);
    int state = lockstate.state;
    return state;
  }
  if( NULL!=db ){ 
    sqlite3_close(db); /* need to close even if open returns an error */
  }
  return SQLITE_LOCKSTATE_ERROR;
}

#endif /* SQLITE_ENABLE_APPLE_SPI */

#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** Obtain a snapshot handle for the snapshot of database zDb currently 
** being read by handle db.
*/
int sqlite3_snapshot_get(

Changes to src/os.c.

206
207
208
209
210
211
212

213
214
215
216
217





218
219
220
221
222
223
224
225
  sqlite3_vfs *pVfs,
  const char *zPath,
  sqlite3_file *pFile,
  int flags,
  int *pFlagsOut
){
  int rc;

  DO_OS_MALLOC_TEST(0);
  /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
  ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
  ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
  ** reaching the VFS. */





  rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
  assert( rc==SQLITE_OK || pFile->pMethods==0 );
  return rc;
}
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  DO_OS_MALLOC_TEST(0);
  assert( dirSync==0 || dirSync==1 );
  return pVfs->xDelete(pVfs, zPath, dirSync);







>





>
>
>
>
>
|







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
  sqlite3_vfs *pVfs,
  const char *zPath,
  sqlite3_file *pFile,
  int flags,
  int *pFlagsOut
){
  int rc;
  int openFlags;
  DO_OS_MALLOC_TEST(0);
  /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
  ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
  ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
  ** reaching the VFS. */
#if SQLITE_ENABLE_DATA_PROTECTION
  openFlags = flags & (0x1087f7f | SQLITE_OPEN_FILEPROTECTION_MASK);
#else
  openFlags = flags & 0x1087f7f;
#endif
  rc = pVfs->xOpen(pVfs, zPath, pFile, openFlags, pFlagsOut);
  assert( rc==SQLITE_OK || pFile->pMethods==0 );
  return rc;
}
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  DO_OS_MALLOC_TEST(0);
  assert( dirSync==0 || dirSync==1 );
  return pVfs->xDelete(pVfs, zPath, dirSync);

Changes to src/os_unix.c.

97
98
99
100
101
102
103

104
105
106
107
108
109
110
...
233
234
235
236
237
238
239
240
241
242



243
244
245
246
247
248
249
...
320
321
322
323
324
325
326




























































































































































































































































































327
328
329
330
331
332
333
....
1304
1305
1306
1307
1308
1309
1310










1311
1312

1313
1314
1315
1316
1317
1318
1319
....
1525
1526
1527
1528
1529
1530
1531





1532
1533

1534
1535
1536
1537
1538
1539
1540
....
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
....
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
....
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799



1800

1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
....
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
....
1952
1953
1954
1955
1956
1957
1958
1959
1960



1961

1962
1963
1964
1965
1966
1967
1968
1969
1970

1971



1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982



1983




1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994




1995
1996
1997
1998
1999
2000
2001
2002




2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013







2014
2015

2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031







2032
2033

2034
2035
2036
2037
2038
2039
2040
....
2182
2183
2184
2185
2186
2187
2188















2189


2190
2191
2192
2193
2194
2195
2196
....
2348
2349
2350
2351
2352
2353
2354



2355

2356
2357
2358
2359
2360
2361
2362
....
2430
2431
2432
2433
2434
2435
2436



2437





2438
2439
2440
2441
2442
2443
2444
....
3547
3548
3549
3550
3551
3552
3553






3554
3555
3556
3557
3558
3559
3560
....
3611
3612
3613
3614
3615
3616
3617








3618

3619
3620
3621
3622
3623
3624
3625
....
3742
3743
3744
3745
3746
3747
3748






3749

3750
3751
3752
3753
3754

3755
3756
3757
3758
3759
3760
3761
....
3849
3850
3851
3852
3853
3854
3855

3856
3857
3858
3859
3860
3861
3862
....
3905
3906
3907
3908
3909
3910
3911














































































































































































































































































































3912
3913
3914
3915
3916
3917
3918
....
4038
4039
4040
4041
4042
4043
4044




















4045
4046
4047
4048
4049
4050
4051
....
4468
4469
4470
4471
4472
4473
4474




4475
4476
4477
4478
4479
4480
4481
....
4535
4536
4537
4538
4539
4540
4541

4542
4543
4544
4545














4546
4547
4548
4549
4550
4551
4552
....
4571
4572
4573
4574
4575
4576
4577







4578
4579
4580
4581
4582
4583
4584
....
4954
4955
4956
4957
4958
4959
4960
4961

4962



4963
4964
4965
4966
4967
4968
4969
....
4972
4973
4974
4975
4976
4977
4978
























































































































































































































































































































































































































4979
4980
4981
4982
4983
4984
4985
....
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
....
5547
5548
5549
5550
5551
5552
5553


5554
5555
5556
5557
5558
5559
5560
....
5927
5928
5929
5930
5931
5932
5933

5934



5935
5936
5937
5938
5939
5940
5941
....
6039
6040
6041
6042
6043
6044
6045




6046
6047
6048
6049
6050
6051
6052
....
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
....
6140
6141
6142
6143
6144
6145
6146





6147
6148
6149
6150
6151
6152
6153
....
6159
6160
6161
6162
6163
6164
6165


6166
6167
6168
6169
6170
6171



6172

6173
6174
6175
6176
6177
6178
6179
....
6219
6220
6221
6222
6223
6224
6225





6226

6227
6228
6229
6230
6231
6232
6233
....
6850
6851
6852
6853
6854
6855
6856


























6857
6858
6859
6860
6861
6862
6863
....
6900
6901
6902
6903
6904
6905
6906

6907
6908
6909
6910
6911
6912
6913
....
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072

7073
7074
7075
7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105



7106













7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
....
7297
7298
7299
7300
7301
7302
7303






7304

7305
7306
7307
7308
7309
7310
7311
....
7540
7541
7542
7543
7544
7545
7546



7547
7548
7549
7550
7551
7552
7553
....
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
....
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
#include <errno.h>
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
# include <sys/mman.h>
#endif

#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>

# include <sys/file.h>
# include <sys/param.h>
#endif /* SQLITE_ENABLE_LOCKING_STYLE */

/*
** Try to determine if gethostuuid() is available based on standard
** macros.  This might sometimes compute the wrong value for some
................................................................................
  sqlite3_int64 mmapSize;             /* Usable size of mapping at pMapRegion */
  sqlite3_int64 mmapSizeActual;       /* Actual size of mapping at pMapRegion */
  sqlite3_int64 mmapSizeMax;          /* Configured FCNTL_MMAP_SIZE value */
  void *pMapRegion;                   /* Memory mapped region */
#endif
  int sectorSize;                     /* Device sector size */
  int deviceCharacteristics;          /* Precomputed device characteristics */
#if SQLITE_ENABLE_LOCKING_STYLE
  int openFlags;                      /* The flags specified at open() */
#endif



#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  unsigned fsFlags;                   /* cached details from statfs() */
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  unsigned iBusyTimeout;              /* Wait this many millisec on locks */
#endif
#if OS_VXWORKS
................................................................................
** testing and debugging only.
*/
#if SQLITE_THREADSAFE
#define threadid pthread_self()
#else
#define threadid 0
#endif





























































































































































































































































































/*
** HAVE_MREMAP defaults to true on Linux and false everywhere else.
*/
#if !defined(HAVE_MREMAP)
# if defined(__linux__) && defined(_GNU_SOURCE)
#  define HAVE_MREMAP 1
................................................................................
static void closePendingFds(unixFile *pFile){
  unixInodeInfo *pInode = pFile->pInode;
  UnixUnusedFd *p;
  UnixUnusedFd *pNext;
  assert( unixFileMutexHeld(pFile) );
  for(p=pInode->pUnused; p; p=pNext){
    pNext = p->pNext;










    robust_close(pFile, p->fd, __LINE__);
    sqlite3_free(p);

  }
  pInode->pUnused = 0;
}

/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
................................................................................
  if( !reserved && !pFile->pInode->bProcessLock ){
    struct flock lock;
    lock.l_whence = SEEK_SET;
    lock.l_start = RESERVED_BYTE;
    lock.l_len = 1;
    lock.l_type = F_WRLCK;
    if( osFcntl(pFile->h, F_GETLK, &lock) ){





      rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
      storeLastErrno(pFile, errno);

    } else if( lock.l_type!=F_UNLCK ){
      reserved = 1;
    }
  }
#endif
  
  sqlite3_mutex_leave(pFile->pInode->pLockMutex);
................................................................................
** This function is a pass-through to fcntl(F_SETLK) if pFile is using
** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
** and is read-only.
**
** Zero is returned if the call completes successfully, or -1 if a call
** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
*/
static int unixFileLock(unixFile *pFile, struct flock *pLock){
  int rc;
  unixInodeInfo *pInode = pFile->pInode;
  assert( pInode!=0 );
  assert( sqlite3_mutex_held(pInode->pLockMutex) );
  if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
    if( pInode->bProcessLock==0 ){
      struct flock lock;
................................................................................
  lock.l_len = 1L;
  lock.l_whence = SEEK_SET;
  if( eFileLock==SHARED_LOCK 
      || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
  ){
    lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
    lock.l_start = PENDING_BYTE;
    if( unixFileLock(pFile, &lock) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }
  }


................................................................................
    assert( pInode->nShared==0 );
    assert( pInode->eFileLock==0 );
    assert( rc==SQLITE_OK );

    /* Now get the read-lock */
    lock.l_start = SHARED_FIRST;
    lock.l_len = SHARED_SIZE;
    if( unixFileLock(pFile, &lock) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    }

    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
      /* This could happen with a network mount */
      tErrno = errno;



      rc = SQLITE_IOERR_UNLOCK; 

    }

    if( rc ){
      if( rc!=SQLITE_BUSY ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }else{
      pFile->eFileLock = SHARED_LOCK;
      pInode->nLock++;
      pInode->nShared = 1;
................................................................................
      lock.l_start = RESERVED_BYTE;
      lock.l_len = 1L;
    }else{
      lock.l_start = SHARED_FIRST;
      lock.l_len = SHARED_SIZE;
    }

    if( unixFileLock(pFile, &lock) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
        storeLastErrno(pFile, tErrno);
      }
    }
  }
................................................................................
        int tErrno;               /* Error code from system call errors */
        off_t divSize = SHARED_SIZE - 1;
        
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;



          rc = SQLITE_IOERR_UNLOCK;

          storeLastErrno(pFile, tErrno);
          goto end_unlock;
        }
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;

          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);



          if( IS_LOCK_ERROR(rc) ){
            storeLastErrno(pFile, tErrno);
          }
          goto end_unlock;
        }
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST+divSize;
        lock.l_len = SHARED_SIZE-divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;



          rc = SQLITE_IOERR_UNLOCK;




          storeLastErrno(pFile, tErrno);
          goto end_unlock;
        }
      }else
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
      {
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        if( unixFileLock(pFile, &lock) ){




          /* In theory, the call to unixFileLock() cannot fail because another
          ** process is holding an incompatible lock. If it does, this 
          ** indicates that the other process is not following the locking
          ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
          ** SQLITE_BUSY would confuse the upper layer (in practice it causes 
          ** an assert to fail). */ 
          rc = SQLITE_IOERR_RDLOCK;
          storeLastErrno(pFile, errno);




          goto end_unlock;
        }
      }
    }
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = PENDING_BYTE;
    lock.l_len = 2L;  assert( PENDING_BYTE+1==RESERVED_BYTE );
    if( unixFileLock(pFile, &lock)==0 ){
      pInode->eFileLock = SHARED_LOCK;
    }else{







      rc = SQLITE_IOERR_UNLOCK;
      storeLastErrno(pFile, errno);

      goto end_unlock;
    }
  }
  if( eFileLock==NO_LOCK ){
    /* Decrement the shared lock counter.  Release the lock using an
    ** OS call only when all threads in this same process have released
    ** the lock.
    */
    pInode->nShared--;
    if( pInode->nShared==0 ){
      lock.l_type = F_UNLCK;
      lock.l_whence = SEEK_SET;
      lock.l_start = lock.l_len = 0L;
      if( unixFileLock(pFile, &lock)==0 ){
        pInode->eFileLock = NO_LOCK;
      }else{







        rc = SQLITE_IOERR_UNLOCK;
        storeLastErrno(pFile, errno);

        pInode->eFileLock = NO_LOCK;
        pFile->eFileLock = NO_LOCK;
      }
    }

    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close
................................................................................
  return SQLITE_OK;
}

/*
** Close the file.
*/
static int nolockClose(sqlite3_file *id) {















  return closeUnixFile(id);


}

/******************* End of the no-op lock implementation *********************
******************************************************************************/

/******************************************************************************
************************* Begin dot-file Locking ******************************
................................................................................
  assert( eFileLock==NO_LOCK );
  rc = osRmdir(zLockFile);
  if( rc<0 ){
    int tErrno = errno;
    if( tErrno==ENOENT ){
      rc = SQLITE_OK;
    }else{



      rc = SQLITE_IOERR_UNLOCK;

      storeLastErrno(pFile, tErrno);
    }
    return rc; 
  }
  pFile->eFileLock = NO_LOCK;
  return SQLITE_OK;
}
................................................................................
    int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
    if( !lrc ){
      /* got the lock, unlock it */
      lrc = robust_flock(pFile->h, LOCK_UN);
      if ( lrc ) {
        int tErrno = errno;
        /* unlock failed with an error */



        lrc = SQLITE_IOERR_UNLOCK; 





        storeLastErrno(pFile, tErrno);
        rc = lrc;
      }
    } else {
      int tErrno = errno;
      reserved = 1;
      /* someone else might have it reserved */
................................................................................
*/
#ifdef F_FULLFSYNC
# define HAVE_FULLFSYNC 1
#else
# define HAVE_FULLFSYNC 0
#endif








/*
** The fsync() system call does not work as advertised on many
** unix systems.  The following procedure is an attempt to make
** it work better.
**
** The SQLITE_NO_SYNC macro disables all fsync()s.  This is useful
................................................................................
#ifdef SQLITE_NO_SYNC
  {
    struct stat buf;
    rc = osFstat(fd, &buf);
  }
#elif HAVE_FULLFSYNC
  if( fullSync ){








    rc = osFcntl(fd, F_FULLFSYNC, 0);

  }else{
    rc = 1;
  }
  /* If the FULLFSYNC failed, fall back to attempting an fsync().
  ** It shouldn't be possible for fullfsync to fail on the local 
  ** file system (on OSX), so failure indicates that FULLFSYNC
  ** isn't supported for this file system. So, attempt an fsync 
................................................................................
  if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
    int dirfd;
    OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
            HAVE_FULLFSYNC, isFullsync));
    rc = osOpenDirectory(pFile->zPath, &dirfd);
    if( rc==SQLITE_OK ){
      full_fsync(dirfd, 0, 0);






      robust_close(pFile, dirfd, __LINE__);

    }else{
      assert( rc==SQLITE_CANTOPEN );
      rc = SQLITE_OK;
    }
    pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;

  }
  return rc;
}

/*
** Truncate an open file to a specified size
*/
................................................................................
*/
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
  if( pFile->szChunk>0 ){
    i64 nSize;                    /* Required file size */
    struct stat buf;              /* Used to hold return values of fstat() */
   
    if( osFstat(pFile->h, &buf) ){

      return SQLITE_IOERR_FSTAT;
    }

    nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
    if( nSize>(i64)buf.st_size ){

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
................................................................................
    rc = unixMapfile(pFile, nByte);
    return rc;
  }
#endif

  return SQLITE_OK;
}















































































































































































































































































































/*
** If *pArg is initially negative then this is a query.  Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
**
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
*/
................................................................................
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
    case SQLITE_FCNTL_SET_LOCKPROXYFILE:
    case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
      return proxyFileControl(id,op,pArg);
    }
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */




















  }
  return SQLITE_NOTFOUND;
}

/*
** If pFd->sectorSize is non-zero when this function is called, it is a
** no-op. Otherwise, the values of pFd->sectorSize and 
................................................................................
  if( rc==SQLITE_OK ){
    assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK );
    rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
  }
  return rc;
}





/*
** Open a shared-memory area associated with open database file pDbFd.  
** This particular implementation uses mmapped files.
**
** The file used to implement shared-memory is in the same directory
** as the open database file and has the same name as the open database
** file with the "-shm" suffix added.  For example, if the database file
................................................................................
#endif

    /* Call fstat() to figure out the permissions on the database file. If
    ** a new *-shm file is created, an attempt will be made to create it
    ** with the same permissions.
    */
    if( osFstat(pDbFd->h, &sStat) ){

      rc = SQLITE_IOERR_FSTAT;
      goto shm_open_err;
    }















#ifdef SQLITE_SHM_DIRECTORY
    nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31;
#else
    nShmFilename = 6 + (int)strlen(zBasePath);
#endif
    pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
    if( pShmNode==0 ){
................................................................................
      if( pShmNode->pShmMutex==0 ){
        rc = SQLITE_NOMEM_BKPT;
        goto shm_open_err;
      }
    }

    if( pInode->bProcessLock==0 ){







      if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
        pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW,
                                     (sStat.st_mode&0777));
      }
      if( pShmNode->hShm<0 ){
        pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW,
                                     (sStat.st_mode&0777));
................................................................................
  /* If pShmNode->nRef has reached 0, then close the underlying
  ** shared-memory file, too */
  assert( unixFileMutexNotheld(pDbFd) );
  unixEnterMutex();
  assert( pShmNode->nRef>0 );
  pShmNode->nRef--;
  if( pShmNode->nRef==0 ){
    if( deleteFlag && pShmNode->hShm>=0 ){

      osUnlink(pShmNode->zFilename);



    }
    unixShmPurge(pDbFd);
  }
  unixLeaveMutex();

  return SQLITE_OK;
}
................................................................................
#else
# define unixShmMap     0
# define unixShmLock    0
# define unixShmBarrier 0
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */

























































































































































































































































































































































































































#if SQLITE_MAX_MMAP_SIZE>0
/*
** If it is currently memory mapped, unmap file pFd.
*/
static void unixUnmapfile(unixFile *pFd){
  assert( pFd->nFetchOut==0 );
  if( pFd->pMapRegion ){
................................................................................
static int proxyClose(sqlite3_file*);
static int proxyLock(sqlite3_file*, int);
static int proxyUnlock(sqlite3_file*, int);
static int proxyCheckReservedLock(sqlite3_file*, int*);
IOMETHODS(
  proxyIoFinder,            /* Finder function name */
  proxyIoMethods,           /* sqlite3_io_methods object name */
  1,                        /* shared memory is disabled */
  proxyClose,               /* xClose method */
  proxyLock,                /* xLock method */
  proxyUnlock,              /* xUnlock method */
  proxyCheckReservedLock,   /* xCheckReservedLock method */
  0                         /* xShmMap method */
)
#endif
................................................................................
#endif
  }

  if( pLockingStyle == &posixIoMethods
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
    || pLockingStyle == &nfsIoMethods
#endif


  ){
    unixEnterMutex();
    rc = findInodeInfo(pNew, &pNew->pInode);
    if( rc!=SQLITE_OK ){
      /* If an error occurred in findInodeInfo(), close the file descriptor
      ** immediately, before releasing the mutex. findInodeInfo() may fail
      ** in two scenarios:
................................................................................
  sqlite3_file *pFile,         /* The file descriptor to be filled in */
  int flags,                   /* Input flags to control the opening */
  int *pOutFlags               /* Output flags returned to SQLite core */
){
  unixFile *p = (unixFile *)pFile;
  int fd = -1;                   /* File descriptor returned by open() */
  int openFlags = 0;             /* Flags to pass to open() */

  int eType = flags&0x0FFF00;  /* Type of file to open */



  int noLock;                    /* True to omit locking primitives */
  int rc = SQLITE_OK;            /* Function Return Code */
  int ctrlFlags = 0;             /* UNIXFILE_* flags */

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);
................................................................................
  ** 'conch file' locking functions later on.  */
  if( isReadonly )  openFlags |= O_RDONLY;
  if( isReadWrite ) openFlags |= O_RDWR;
  if( isCreate )    openFlags |= O_CREAT;
  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW);





  if( fd<0 ){
    mode_t openMode;              /* Permissions to create file with */
    uid_t uid;                    /* Userid for the file */
    gid_t gid;                    /* Groupid for the file */
    rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
    if( rc!=SQLITE_OK ){
      assert( !p->pPreallocatedUnused );
................................................................................
      robust_close(p, fd, __LINE__);
      return SQLITE_NOMEM_BKPT;
    }
#else
    osUnlink(zName);
#endif
  }
#if SQLITE_ENABLE_LOCKING_STYLE
  else{
    p->openFlags = openFlags;
  }
#endif
  
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
  if( fstatfs(fd, &fsInfo) == -1 ){
................................................................................
  /* Set up appropriate ctrlFlags */
  if( isDelete )                ctrlFlags |= UNIXFILE_DELETE;
  if( isReadonly )              ctrlFlags |= UNIXFILE_RDONLY;
  noLock = eType!=SQLITE_OPEN_MAIN_DB;
  if( noLock )                  ctrlFlags |= UNIXFILE_NOLOCK;
  if( isNewJrnl )               ctrlFlags |= UNIXFILE_DIRSYNC;
  if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;






#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
  isAutoProxy = 1;
#endif
  if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
    char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
................................................................................
      useProxy = atoi(envforce)>0;
    }else{
      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
    }
    if( useProxy ){
      rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
      if( rc==SQLITE_OK ){


        rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
        if( rc!=SQLITE_OK ){
          /* Use unixClose to clean up the resources added in fillInUnixFile 
          ** and clear all the structure's references.  Specifically, 
          ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op 
          */



          unixClose(pFile);

          return rc;
        }
      }
      goto open_finished;
    }
  }
#endif
................................................................................
  if( (dirSync & 1)!=0 ){
    int fd;
    rc = osOpenDirectory(zPath, &fd);
    if( rc==SQLITE_OK ){
      if( full_fsync(fd,0,0) ){
        rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
      }





      robust_close(0, fd, __LINE__);

    }else{
      assert( rc==SQLITE_CANTOPEN );
      rc = SQLITE_OK;
    }
  }
#endif
  return rc;
................................................................................
    }
    buf[i] = lockPath[i];
  }
  OSTRACE(("CREATELOCKPATH  proxy lock path=%s pid=%d\n",lockPath,osGetpid(0)));
  return 0;
}



























/*
** Create a new VFS file descriptor (stored in memory obtained from
** sqlite3_malloc) and open the file named "path" in the file descriptor.
**
** The caller is responsible not only for closing the file descriptor
** but also for freeing the memory associated with the file descriptor.
*/
................................................................................
  }
  if( fd<0 ){
    openFlags = O_RDONLY | O_NOFOLLOW;
    fd = robust_open(path, openFlags, 0);
    terrno = errno;
  }
  if( fd<0 ){

    if( islockfile ){
      return SQLITE_BUSY;
    }
    switch (terrno) {
      case EACCES:
        return SQLITE_PERM;
      case EIO: 
................................................................................
/* Take the requested lock on the conch file and break a stale lock if the 
** host id matches.
*/
static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
  proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; 
  unixFile *conchFile = pCtx->conchFile;
  int rc = SQLITE_OK;
  int nTries = 0;
  struct timespec conchModTime;
  
  memset(&conchModTime, 0, sizeof(conchModTime));
  do {
    rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
    nTries ++;
    if( rc==SQLITE_BUSY ){

      /* If the lock failed (busy):
       * 1st try: get the mod time of the conch, wait 0.5s and try again. 
       * 2nd try: fail if the mod time changed or host id is different, wait 
       *           10 sec and try again
       * 3rd try: break the lock unless the mod time has changed.
       */
      struct stat buf;
      if( osFstat(conchFile->h, &buf) ){
        storeLastErrno(pFile, errno);
        return SQLITE_IOERR_LOCK;
      }
      
      if( nTries==1 ){
        conchModTime = buf.st_mtimespec;
        usleep(500000); /* wait 0.5 sec and try the lock again*/
        continue;  
      }

      assert( nTries>1 );
      if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || 
         conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
        return SQLITE_BUSY;
      }
      
      if( nTries==2 ){  
        char tBuf[PROXY_MAXCONCHLEN];
        int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
        if( len<0 ){
          storeLastErrno(pFile, errno);
          return SQLITE_IOERR_LOCK;
        }
        if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
          /* don't break the lock if the host id doesn't match */



          if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){













            return SQLITE_BUSY;
          }
        }else{
          /* don't break the lock on short read or a version mismatch */
          return SQLITE_BUSY;
        }
        usleep(10000000); /* wait 10 sec and try the lock again */
        continue; 
      }
      
      assert( nTries==3 );
      if( 0==proxyBreakConchLock(pFile, myHostID) ){
        rc = SQLITE_OK;
        if( lockType==EXCLUSIVE_LOCK ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
        }
        if( !rc ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
        }
      }
    }
  } while( rc==SQLITE_BUSY && nTries<3 );
  
  return rc;
}

/* Takes the conch by taking a shared lock and read the contents conch, if 
** lockPath is non-NULL, the host ID and lock file path must match.  A NULL 
** lockPath means that the lockPath in the conch file will be used if the 
................................................................................
      conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
      
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        int fd;
        if( pFile->h>=0 ){






          robust_close(pFile, pFile->h, __LINE__);

        }
        pFile->h = -1;
        fd = robust_open(pCtx->dbPath, pFile->openFlags, 0);
        OSTRACE(("TRANSPROXY: OPEN  %d\n", fd));
        if( fd>=0 ){
          pFile->h = fd;
        }else{
................................................................................
        pCtx->conchHeld = -1; /* read only FS/ lockless */
        rc = SQLITE_OK;
      }
    }
  }  
  if( rc==SQLITE_OK && lockPath ){
    pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);



  }

  if( rc==SQLITE_OK ){
    pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
    if( pCtx->dbPath==NULL ){
      rc = SQLITE_NOMEM_BKPT;
    }
................................................................................
** This routine handles sqlite3_file_control() calls that are specific
** to proxy locking.
*/
static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
  switch( op ){
    case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
      unixFile *pFile = (unixFile*)id;
      if( pFile->pMethod == &proxyIoMethods ){
        proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
        proxyTakeConch(pFile);
        if( pCtx->lockProxyPath ){
          *(const char **)pArg = pCtx->lockProxyPath;
        }else{
          *(const char **)pArg = ":auto: (not held)";
        }
................................................................................
        *(const char **)pArg = NULL;
      }
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SET_LOCKPROXYFILE: {
      unixFile *pFile = (unixFile*)id;
      int rc = SQLITE_OK;
      int isProxyStyle = (pFile->pMethod == &proxyIoMethods);
      if( pArg==NULL || (const char *)pArg==0 ){
        if( isProxyStyle ){
          /* turn off proxy locking - not supported.  If support is added for
          ** switching proxy locking mode off then it will need to fail if
          ** the journal mode is WAL mode. 
          */
          rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;







>







 







|


>
>
>







 







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







 







>
>
>
>
>
>
>
>
>
>


>







 







>
>
>
>
>


>







 







|







 







|


|







 







|








|


>
>
>

>



|







 







|







 







|

>
>
>

>







|

>

>
>
>









|

>
>
>

>
>
>
>










|
>
>
>
>







|
>
>
>
>








|


>
>
>
>
>
>
>


>













|


>
>
>
>
>
>
>


>







 







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







 







>
>
>

>







 







>
>
>

>
>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>
>
>
>
>

>







 







>
>
>
>
>
>

>





>







 







>







 







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







 







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







 







>
>
>
>







 







>




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







 







>
>
>
>
>
>
>







 







|
>
|
>
>
>







 







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







 







|







 







>
>







 







>
|
>
>
>







 







>
>
>
>







 







|







 







>
>
>
>
>







 







>
>






>
>
>
|
>







 







>
>
>
>
>

>







 







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







 







>







 







<





<

>












|





|





|







|
>
>
>

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










|
|









|







 







>
>
>
>
>
>

>







 







>
>
>







 







|







 







|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
...
324
325
326
327
328
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
411
412
413
414
415
416
417
418
419
420
421
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
524
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
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
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
....
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
....
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
....
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
....
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
....
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
....
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
....
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
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
....
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
....
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
....
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
....
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
....
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
....
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
....
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
....
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
....
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
....
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
....
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
....
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
....
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
....
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
....
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
....
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
....
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
....
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
....
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
....
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
....
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
....
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
....
8038
8039
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
....
8114
8115
8116
8117
8118
8119
8120
8121
8122
8123
8124
8125
8126
8127
8128
....
8273
8274
8275
8276
8277
8278
8279

8280
8281
8282
8283
8284

8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363
8364
8365
....
8527
8528
8529
8530
8531
8532
8533
8534
8535
8536
8537
8538
8539
8540
8541
8542
8543
8544
8545
8546
8547
8548
....
8777
8778
8779
8780
8781
8782
8783
8784
8785
8786
8787
8788
8789
8790
8791
8792
8793
....
8819
8820
8821
8822
8823
8824
8825
8826
8827
8828
8829
8830
8831
8832
8833
....
8835
8836
8837
8838
8839
8840
8841
8842
8843
8844
8845
8846
8847
8848
8849
#include <errno.h>
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
# include <sys/mman.h>
#endif

#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
# include <uuid/uuid.h>
# include <sys/file.h>
# include <sys/param.h>
#endif /* SQLITE_ENABLE_LOCKING_STYLE */

/*
** Try to determine if gethostuuid() is available based on standard
** macros.  This might sometimes compute the wrong value for some
................................................................................
  sqlite3_int64 mmapSize;             /* Usable size of mapping at pMapRegion */
  sqlite3_int64 mmapSizeActual;       /* Actual size of mapping at pMapRegion */
  sqlite3_int64 mmapSizeMax;          /* Configured FCNTL_MMAP_SIZE value */
  void *pMapRegion;                   /* Memory mapped region */
#endif
  int sectorSize;                     /* Device sector size */
  int deviceCharacteristics;          /* Precomputed device characteristics */
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  int openFlags;                      /* The flags specified at open() */
#endif
#if SQLITE_ENABLE_DATA_PROTECTION
  int protFlags;                      /* Data protection flags from unixOpen */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  unsigned fsFlags;                   /* cached details from statfs() */
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
  unsigned iBusyTimeout;              /* Wait this many millisec on locks */
#endif
#if OS_VXWORKS
................................................................................
** testing and debugging only.
*/
#if SQLITE_THREADSAFE
#define threadid pthread_self()
#else
#define threadid 0
#endif

#ifdef __APPLE__
#define SQLITE_ENABLE_SUPERLOCK 1
#endif

#if SQLITE_ENABLE_SUPERLOCK
#include "sqlite3.h"
#include <string.h>
#include <assert.h>

/*
** A structure to collect a busy-handler callback and argument and a count
** of the number of times it has been invoked.
*/
struct SuperlockBusy {
  int (*xBusy)(void*,int);        /* Pointer to busy-handler function */
  void *pBusyArg;                 /* First arg to pass to xBusy */
  int nBusy;                      /* Number of times xBusy has been invoked */
};
typedef struct SuperlockBusy SuperlockBusy;

/*
** An instance of the following structure is allocated for each active
** superlock. The opaque handle returned by sqlite3demo_superlock() is
** actually a pointer to an instance of this structure.
*/
struct Superlock {
  sqlite3 *db;                    /* Database handle used to lock db */
  int bWal;                       /* True if db is a WAL database */
};
typedef struct Superlock Superlock;

/*
** The pCtx pointer passed to this function is actually a pointer to a
** SuperlockBusy structure. Invoke the busy-handler function encapsulated
** by the structure and return the result.
*/
static int superlockBusyHandler(void *pCtx, int UNUSED){
  SuperlockBusy *pBusy = (SuperlockBusy *)pCtx;
  if( pBusy->xBusy==0 ) return 0;
  return pBusy->xBusy(pBusy->pBusyArg, pBusy->nBusy++);
}

/*
** This function is used to determine if the main database file for 
** connection db is open in WAL mode or not. If no error occurs and the
** database file is in WAL mode, set *pbWal to true and return SQLITE_OK.
** If it is not in WAL mode, set *pbWal to false.
**
** If an error occurs, return an SQLite error code. The value of *pbWal
** is undefined in this case.
*/
static int superlockIsWal(Superlock *pLock){
  int rc;                         /* Return Code */
  sqlite3_stmt *pStmt;            /* Compiled PRAGMA journal_mode statement */

  rc = sqlite3_prepare(pLock->db, "PRAGMA main.journal_mode", -1, &pStmt, 0);
  if( rc!=SQLITE_OK ) return rc;

  pLock->bWal = 0;
  if( SQLITE_ROW==sqlite3_step(pStmt) ){
    const char *zMode = (const char *)sqlite3_column_text(pStmt, 0);
    if( zMode && strlen(zMode)==3 && sqlite3_strnicmp("wal", zMode, 3)==0 ){
      pLock->bWal = 1;
    }
  }

  return sqlite3_finalize(pStmt);
}

/*
** Obtain an exclusive shm-lock on nByte bytes starting at offset idx
** of the file fd. If the lock cannot be obtained immediately, invoke
** the busy-handler until either it is obtained or the busy-handler
** callback returns 0.
*/
static int superlockShmLock(
  sqlite3_file *fd,               /* Database file handle */
  int idx,                        /* Offset of shm-lock to obtain */
  int nByte,                      /* Number of consective bytes to lock */
  SuperlockBusy *pBusy            /* Busy-handler wrapper object */
){
  int rc;
  int (*xShmLock)(sqlite3_file*, int, int, int) = fd->pMethods->xShmLock;
  do {
    rc = xShmLock(fd, idx, nByte, SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE);
  }while( rc==SQLITE_BUSY && superlockBusyHandler((void *)pBusy, 0) );
  return rc;
}

/*
** Obtain the extra locks on the database file required for WAL databases.
** Invoke the supplied busy-handler as required.
*/
static int superlockWalLock(
  sqlite3 *db,                    /* Database handle open on WAL database */
  SuperlockBusy *pBusy            /* Busy handler wrapper object */
){
  int rc;                         /* Return code */
  sqlite3_file *fd = 0;           /* Main database file handle */
  void volatile *p = 0;           /* Pointer to first page of shared memory */

  /* Obtain a pointer to the sqlite3_file object open on the main db file. */
  rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
  if( rc!=SQLITE_OK ) return rc;

  /* Obtain the "recovery" lock. Normally, this lock is only obtained by
  ** clients running database recovery.  
  */
  rc = superlockShmLock(fd, 2, 1, pBusy);
  if( rc!=SQLITE_OK ) return rc;

  /* Zero the start of the first shared-memory page. This means that any
  ** clients that open read or write transactions from this point on will
  ** have to run recovery before proceeding. Since they need the "recovery"
  ** lock that this process is holding to do that, no new read or write
  ** transactions may now be opened. Nor can a checkpoint be run, for the
  ** same reason.
  */
  rc = fd->pMethods->xShmMap(fd, 0, 32*1024, 1, &p);
  if( rc!=SQLITE_OK ) return rc;
  memset((void *)p, 0, 32);

  /* Obtain exclusive locks on all the "read-lock" slots. Once these locks
  ** are held, it is guaranteed that there are no active reader, writer or 
  ** checkpointer clients.
  */
  rc = superlockShmLock(fd, 3, SQLITE_SHM_NLOCK-3, pBusy);
  return rc;
}

/*
** Release a superlock held on a database file. The argument passed to 
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
static void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER,
                             (void *)&fd);
    if( rc==SQLITE_OK ){
      fd->pMethods->xShmLock(fd, 2, 1, flags);
      fd->pMethods->xShmLock(fd, 3, SQLITE_SHM_NLOCK-3, flags);
    }
  }
  sqlite3_close(p->db);
  sqlite3_free(p);
}

/*
** Obtain a superlock on the database file identified by zPath, using the
** locking primitives provided by VFS zVfs. If successful, SQLITE_OK is
** returned and output variable *ppLock is populated with an opaque handle
** that may be used with sqlite3demo_superunlock() to release the lock.
**
** If an error occurs, *ppLock is set to 0 and an SQLite error code 
** (e.g. SQLITE_BUSY) is returned.
**
** If a required lock cannot be obtained immediately and the xBusy parameter
** to this function is not NULL, then xBusy is invoked in the same way
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
static int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */
  int flags,                   /* Additional flags to pass to sqlite3_open_v2 */
  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;

  pLock = sqlite3_malloc(sizeof(Superlock));
  if( !pLock ) return SQLITE_NOMEM;
  memset(pLock, 0, sizeof(Superlock));

  /* Open a database handle on the file to superlock. */
  rc = sqlite3_open_v2(
      zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|flags, zVfs
  );

  /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
  ** a WAL database, this is all we need to do.  
  **
  ** A wrapper function is used to invoke the busy-handler instead of
  ** registering the busy-handler function supplied by the user directly
  ** with SQLite. This is because the same busy-handler function may be
  ** invoked directly later on when attempting to obtain the extra locks
  ** required in WAL mode. By using the wrapper, we are able to guarantee
  ** that the "nBusy" integer parameter passed to the users busy-handler
  ** represents the total number of busy-handler invocations made within
  ** this call to sqlite3demo_superlock(), including any made during the
  ** "BEGIN EXCLUSIVE".
  */
  if( rc==SQLITE_OK ){
    busy.xBusy = xBusy;
    busy.pBusyArg = pBusyArg;
    sqlite3_busy_handler(pLock->db, superlockBusyHandler, (void *)&busy);
    rc = sqlite3_exec(pLock->db, "BEGIN EXCLUSIVE", 0, 0, 0);
  }

  /* If the BEGIN EXCLUSIVE was executed successfully and this is a WAL
  ** database, call superlockWalLock() to obtain the extra locks required
  ** to prevent readers, writers and/or checkpointers from accessing the
  ** db while this process is holding the superlock.
  **
  ** Before attempting any WAL locks, commit the transaction started above
  ** to drop the WAL read and write locks currently held. Otherwise, the
  ** new WAL locks may conflict with the old.
  */
  if( rc==SQLITE_OK ){
    if( SQLITE_OK==(rc = superlockIsWal(pLock)) && pLock->bWal ){
      rc = sqlite3_exec(pLock->db, "COMMIT", 0, 0, 0);
      if( rc==SQLITE_OK ){
        rc = superlockWalLock(pLock->db, &busy);
      }
    }
  }

  if( rc!=SQLITE_OK ){
    sqlite3demo_superunlock(pLock);
    *ppLock = 0;
  }else{
    *ppLock = pLock;
  }

  return rc;
}

/* A corrupt DB won't work with the sql-based locking attempt, grab an 
** exclusive lock and return SQLITE_OK or SQLITE_BUSY if the lock fails 
** returns the current lock level held on sqlite3_file
*/
static int sqlite3demo_superlock_corrupt(
  sqlite3_file *id,
  int eTargetFileLock,
  int *pFileLock
){
  unixFile *pFile = (unixFile*)id;
  int eFileLock = pFile->eFileLock;
  int rc = SQLITE_OK;
  
  if( eFileLock<eTargetFileLock ){
    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
  }
  if( !rc && SQLITE_LOCK_SHARED<eTargetFileLock ){
    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
  }
  if( rc ){
    if( pFile->eFileLock > eFileLock ){
      pFile->pMethod->xUnlock(id, eFileLock);
    }
    return rc;
  }
  if (pFileLock) {
    *pFileLock = eFileLock;
  }
  return SQLITE_OK;
}

static int sqlite3demo_superunlock_corrupt(sqlite3_file *id, int eFileLock) {
  unixFile *pFile = (unixFile*)id;
  int rc = SQLITE_OK;
  
  if( pFile->eFileLock > eFileLock ){
    rc = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
  }
  if( pFile->eFileLock > eFileLock ){
    int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
    if (!rc) rc = unlockRC;
  }
  return rc;
}

#endif /* SQLITE_ENABLE_SUPERLOCK */


/*
** HAVE_MREMAP defaults to true on Linux and false everywhere else.
*/
#if !defined(HAVE_MREMAP)
# if defined(__linux__) && defined(_GNU_SOURCE)
#  define HAVE_MREMAP 1
................................................................................
static void closePendingFds(unixFile *pFile){
  unixInodeInfo *pInode = pFile->pInode;
  UnixUnusedFd *p;
  UnixUnusedFd *pNext;
  assert( unixFileMutexHeld(pFile) );
  for(p=pInode->pUnused; p; p=pNext){
    pNext = p->pNext;
#if OSCLOSE_CHECK_CLOSE_IOERR
    if( close(p->fd) ){
      storeLastErrno(pFile, errno);
      rc = SQLITE_IOERR_CLOSE;
      p->pNext = pError;
      pError = p;
    }else{
      sqlite3_free(p);
    }
#else
    robust_close(pFile, p->fd, __LINE__);
    sqlite3_free(p);
#endif
  }
  pInode->pUnused = 0;
}

/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
................................................................................
  if( !reserved && !pFile->pInode->bProcessLock ){
    struct flock lock;
    lock.l_whence = SEEK_SET;
    lock.l_start = RESERVED_BYTE;
    lock.l_len = 1;
    lock.l_type = F_WRLCK;
    if( osFcntl(pFile->h, F_GETLK, &lock) ){
#if OSLOCKING_CHECK_BUSY_IOERR
      int tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
      storeLastErrno(pFile, tErrno);
#else
      rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
      storeLastErrno(pFile, errno);
#endif
    } else if( lock.l_type!=F_UNLCK ){
      reserved = 1;
    }
  }
#endif
  
  sqlite3_mutex_leave(pFile->pInode->pLockMutex);
................................................................................
** This function is a pass-through to fcntl(F_SETLK) if pFile is using
** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
** and is read-only.
**
** Zero is returned if the call completes successfully, or -1 if a call
** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
*/
static int unixFileLock(unixFile *pFile, struct flock *pLock, int nRetry){
  int rc;
  unixInodeInfo *pInode = pFile->pInode;
  assert( pInode!=0 );
  assert( sqlite3_mutex_held(pInode->pLockMutex) );
  if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
    if( pInode->bProcessLock==0 ){
      struct flock lock;
................................................................................
  lock.l_len = 1L;
  lock.l_whence = SEEK_SET;
  if( eFileLock==SHARED_LOCK 
      || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
  ){
    lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
    lock.l_start = PENDING_BYTE;
    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }
  }


................................................................................
    assert( pInode->nShared==0 );
    assert( pInode->eFileLock==0 );
    assert( rc==SQLITE_OK );

    /* Now get the read-lock */
    lock.l_start = SHARED_FIRST;
    lock.l_len = SHARED_SIZE;
    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    }

    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    if( unixFileLock(pFile, &lock, 10) && rc==SQLITE_OK ){
      /* This could happen with a network mount */
      tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); 
#else
      rc = SQLITE_IOERR_UNLOCK; 
#endif
    }

    if( rc ){
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }else{
      pFile->eFileLock = SHARED_LOCK;
      pInode->nLock++;
      pInode->nShared = 1;
................................................................................
      lock.l_start = RESERVED_BYTE;
      lock.l_len = 1L;
    }else{
      lock.l_start = SHARED_FIRST;
      lock.l_len = SHARED_SIZE;
    }

    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
        storeLastErrno(pFile, tErrno);
      }
    }
  }
................................................................................
        int tErrno;               /* Error code from system call errors */
        off_t divSize = SHARED_SIZE - 1;
        
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock, 10)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          storeLastErrno(pFile, tErrno);
          goto end_unlock;
        }
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock, 10)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            storeLastErrno(pFile, tErrno);
          }
          goto end_unlock;
        }
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST+divSize;
        lock.l_len = SHARED_SIZE-divSize;
        if( unixFileLock(pFile, &lock, 10)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            storeLastErrno(pFile, tErrno);
          }
          storeLastErrno(pFile, tErrno);
          goto end_unlock;
        }
      }else
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
      {
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        if( unixFileLock(pFile, &lock, 10) ){
          int tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
#else
          /* In theory, the call to unixFileLock() cannot fail because another
          ** process is holding an incompatible lock. If it does, this 
          ** indicates that the other process is not following the locking
          ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
          ** SQLITE_BUSY would confuse the upper layer (in practice it causes 
          ** an assert to fail). */ 
          rc = SQLITE_IOERR_RDLOCK;
          storeLastErrno(pFile, tErrno);
#endif
          if( IS_LOCK_ERROR(rc) ){
            storeLastErrno(pFile, tErrno);
          }
          goto end_unlock;
        }
      }
    }
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = PENDING_BYTE;
    lock.l_len = 2L;  assert( PENDING_BYTE+1==RESERVED_BYTE );
    if( unixFileLock(pFile, &lock, 10)==0 ){
      pInode->eFileLock = SHARED_LOCK;
    }else{
#if OSLOCKING_CHECK_BUSY_IOERR
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
#else
      rc = SQLITE_IOERR_UNLOCK;
      storeLastErrno(pFile, errno);
#endif
      goto end_unlock;
    }
  }
  if( eFileLock==NO_LOCK ){
    /* Decrement the shared lock counter.  Release the lock using an
    ** OS call only when all threads in this same process have released
    ** the lock.
    */
    pInode->nShared--;
    if( pInode->nShared==0 ){
      lock.l_type = F_UNLCK;
      lock.l_whence = SEEK_SET;
      lock.l_start = lock.l_len = 0L;
      if( unixFileLock(pFile, &lock, 10)==0 ){
        pInode->eFileLock = NO_LOCK;
      }else{
#if OSLOCKING_CHECK_BUSY_IOERR
        tErrno = errno;
        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
        if( IS_LOCK_ERROR(rc) ){
          storeLastErrno(pFile, tErrno);
        }
#else
        rc = SQLITE_IOERR_UNLOCK;
        storeLastErrno(pFile, errno);
#endif
        pInode->eFileLock = NO_LOCK;
        pFile->eFileLock = NO_LOCK;
      }
    }

    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close
................................................................................
  return SQLITE_OK;
}

/*
** Close the file.
*/
static int nolockClose(sqlite3_file *id) {
  int rc = SQLITE_OK;
  unixFile *pFile = (unixFile *)id;
  unixEnterMutex();
  if( pFile->pInode ){  
    assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
    if( pFile->pInode->nLock ){
      /* If there are outstanding locks, do not actually close the file just
      ** yet because that would clear those locks.  Instead, add the file
      ** descriptor to pInode->pUnused list.  It will be automatically closed 
      ** when the last lock is cleared.
      */
      setPendingFd(pFile);
    }
    releaseInodeInfo(pFile);
  }
  rc = closeUnixFile(id);
  unixLeaveMutex();
  return rc;
}

/******************* End of the no-op lock implementation *********************
******************************************************************************/

/******************************************************************************
************************* Begin dot-file Locking ******************************
................................................................................
  assert( eFileLock==NO_LOCK );
  rc = osRmdir(zLockFile);
  if( rc<0 ){
    int tErrno = errno;
    if( tErrno==ENOENT ){
      rc = SQLITE_OK;
    }else{
#if OSLOCKING_CHECK_BUSY_IOERR
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
      rc = SQLITE_IOERR_UNLOCK;
#endif
      storeLastErrno(pFile, tErrno);
    }
    return rc; 
  }
  pFile->eFileLock = NO_LOCK;
  return SQLITE_OK;
}
................................................................................
    int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
    if( !lrc ){
      /* got the lock, unlock it */
      lrc = robust_flock(pFile->h, LOCK_UN);
      if ( lrc ) {
        int tErrno = errno;
        /* unlock failed with an error */
#if OSLOCKING_CHECK_BUSY_IOERR
        lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else 
        lrc = SQLITE_IOERR_UNLOCK; 
#endif
        if( IS_LOCK_ERROR(lrc) ){
          storeLastErrno(pFile, tErrno);
          rc = lrc;
        }
        storeLastErrno(pFile, tErrno);
        rc = lrc;
      }
    } else {
      int tErrno = errno;
      reserved = 1;
      /* someone else might have it reserved */
................................................................................
*/
#ifdef F_FULLFSYNC
# define HAVE_FULLFSYNC 1
#else
# define HAVE_FULLFSYNC 0
#endif

#ifdef SQLITE_USE_REQUEST_FULLFSYNC
#import <notify.h>
#import <libkern/OSAtomic.h>
static OSSpinLock notify_lock = 0;
#define REQUEST_FULLSYNC_NOTIFICATION    "com.apple.reqsync"
#endif

/*
** The fsync() system call does not work as advertised on many
** unix systems.  The following procedure is an attempt to make
** it work better.
**
** The SQLITE_NO_SYNC macro disables all fsync()s.  This is useful
................................................................................
#ifdef SQLITE_NO_SYNC
  {
    struct stat buf;
    rc = osFstat(fd, &buf);
  }
#elif HAVE_FULLFSYNC
  if( fullSync ){
#ifdef SQLITE_USE_REQUEST_FULLFSYNC
    rc = osFsync(fd);
    if (!rc) {
      OSSpinLockLock(&notify_lock);
      rc = notify_post(REQUEST_FULLSYNC_NOTIFICATION);
      OSSpinLockUnlock(&notify_lock);
    }
#else
    rc = osFcntl(fd, F_FULLFSYNC, 0);
#endif
  }else{
    rc = 1;
  }
  /* If the FULLFSYNC failed, fall back to attempting an fsync().
  ** It shouldn't be possible for fullfsync to fail on the local 
  ** file system (on OSX), so failure indicates that FULLFSYNC
  ** isn't supported for this file system. So, attempt an fsync 
................................................................................
  if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
    int dirfd;
    OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
            HAVE_FULLFSYNC, isFullsync));
    rc = osOpenDirectory(pFile->zPath, &dirfd);
    if( rc==SQLITE_OK ){
      full_fsync(dirfd, 0, 0);
#if OSCLOSE_CHECK_CLOSE_IOERR
      if( close(pFile->dirfd) ){
        storeLastErrno(pFile, errno);
        rc = SQLITE_IOERR_DIR_CLOSE;
      }
#else
      robust_close(pFile, dirfd, __LINE__);
#endif
    }else{
      assert( rc==SQLITE_CANTOPEN );
      rc = SQLITE_OK;
    }
    pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;

  }
  return rc;
}

/*
** Truncate an open file to a specified size
*/
................................................................................
*/
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
  if( pFile->szChunk>0 ){
    i64 nSize;                    /* Required file size */
    struct stat buf;              /* Used to hold return values of fstat() */
   
    if( osFstat(pFile->h, &buf) ){
      storeLastErrno(pFile, errno);
      return SQLITE_IOERR_FSTAT;
    }

    nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
    if( nSize>(i64)buf.st_size ){

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
................................................................................
    rc = unixMapfile(pFile, nByte);
    return rc;
  }
#endif

  return SQLITE_OK;
}


#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
#include "sqlite3_private.h"
#include <copyfile.h>
static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath);
#endif

#if SQLITE_ENABLE_LOCKING_STYLE
static int isProxyLockingMode(unixFile *);
#endif

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
static int unixTruncateDatabase(unixFile *, int);

static int unixInvalidateSupportFiles(unixFile *, int);

static int findCreateFileMode(const char *, int, mode_t*, uid_t *,gid_t *);

/* opens a read/write connection to a file zName inheriting the appropriate
** user/perms from the database file if running as root.  Returns the file 
** descriptor by reference
*/
static int unixOpenChildFile(
  const char *zName,
  int openFlags,
  int dbOpenFlags,
  int protFlags,
  int *pFd
){
  int fd = -1;
  mode_t openMode;              /* Permissions to create file with */
  uid_t uid;                    /* Userid for the file */
  gid_t gid;                    /* Groupid for the file */
  int rc;
  
  assert(pFd!=NULL);
  rc = findCreateFileMode(zName, dbOpenFlags, &openMode, &uid, &gid);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  fd = robust_open(zName, openFlags, openMode);
  OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
  if( fd<0 ){
    rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
    return rc;
  }
  /* if we're opening the wal or journal and running as root, set
  ** the journal uid/gid */
  if( dbOpenFlags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    uid_t euid = geteuid();
    if( euid==0 && (euid!=uid || getegid()!=gid) ){
      if( fchown(fd, uid, gid) ){
        rc = SQLITE_CANTOPEN_BKPT;
      }
    }
  }
  if( rc==SQLITE_OK ){
    *pFd = fd;
  } else {
    *pFd = -1;
    close(fd);
  }
  return rc;
}

static int unixReplaceDatabase(unixFile *pFile, sqlite3 *srcdb) {
  sqlite3_file *id = (sqlite3_file *)pFile;
  Btree *pSrcBtree = NULL;
  sqlite3_file *src_file = NULL;
  unixFile *pSrcFile = NULL;
  char srcWalPath[MAXPATHLEN+5];
  int srcWalFD = -1;
  int rc = SQLITE_OK;
  void *pLock = NULL;
  int flags = 0;
  sqlite3 *srcdb2 = NULL;
  copyfile_state_t s;
  int corruptSrcFileLock = 0;
  int corruptDstFileLock = 0;
  int isSrcCorrupt = 0;
  int isDstCorrupt = 0;
  
  if( !sqlite3SafetyCheckOk(srcdb) ){
    return SQLITE_MISUSE;
  }
    
#if SQLITE_ENABLE_DATA_PROTECTION
  flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
  if( isProxyLockingMode(pFile) ){
    flags |= SQLITE_OPEN_AUTOPROXY;
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isDstCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE,
                                         &corruptDstFileLock);
    }
    if( rc ){
      return rc;
    }
  }
  /* get the src file descriptor adhering to the db struct access rules 
   ** this code is modeled after sqlite3_file_control() in main.c
   */ 
  sqlite3_mutex_enter(srcdb->mutex);
  if( srcdb->nDb>0 ){
    pSrcBtree = srcdb->aDb[0].pBt;
  }
  if( pSrcBtree ){
    Pager *pSrcPager;
    sqlite3BtreeEnter(pSrcBtree);
    pSrcPager = sqlite3BtreePager(pSrcBtree);
    assert( pSrcPager!=0 );
    src_file = sqlite3PagerFile(pSrcPager);
    assert( src_file!=0 );
    if( src_file->pMethods ){
      int srcFlags = 0;
      pSrcFile = (unixFile *)src_file;
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
      if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) {
        srcFlags = SQLITE_OPEN_READWRITE;
      } else {
        srcFlags = SQLITE_OPEN_READONLY;
      }
#else
      srcFlags = SQLITE_OPEN_READWRITE;
#endif
#if SQLITE_ENABLE_DATA_PROTECTION
      srcFlags |= pSrcFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
      if( isProxyLockingMode(pSrcFile) ){
        srcFlags |= SQLITE_OPEN_AUTOPROXY;
      }
#endif
      rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
      if( rc==SQLITE_OK ){
        /* start a deferred transaction and read to establish a read lock */
        rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version",
                          0, 0, 0);
        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
          isSrcCorrupt = 1;
          rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED,
                                             &corruptSrcFileLock);
        }
      }
    }
  }
  if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
    rc = SQLITE_INTERNAL;
  }
  if( rc!=SQLITE_OK ){
    goto end_replace_database;
  }
  /* both databases are locked appropriately, copy the src wal journal if 
   ** one exists and then the actual database file
   */
  strlcpy(srcWalPath, pSrcFile->zPath, MAXPATHLEN+5);
  strlcat(srcWalPath, "-wal", MAXPATHLEN+5);
  srcWalFD = open(srcWalPath, O_RDONLY);
  if( !(srcWalFD<0) ){
    char dstWalPath[MAXPATHLEN+5];
    int dstWalFD = -1;
    int protFlags = 0;
    strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
    strlcat(dstWalPath, "-wal", MAXPATHLEN+5);

    rc = unixOpenChildFile(dstWalPath, O_RDWR|O_CREAT, SQLITE_OPEN_WAL,
                           protFlags, &dstWalFD);
    if( rc==SQLITE_OK ){
      s = copyfile_state_alloc();
      lseek(srcWalFD, 0, SEEK_SET);
      lseek(dstWalFD, 0, SEEK_SET);
      if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_DATA) ){
        int err=errno;
        switch(err) {
          case ENOMEM:
            rc = SQLITE_NOMEM;
            break;
          default:
            storeLastErrno(pFile, err);
            rc = SQLITE_IOERR;
        }
      }
      copyfile_state_free(s);
      close(dstWalFD);
    }
    close(srcWalFD);
  }
  if( rc==SQLITE_OK ){
    /* before we copy, ensure that the file change counter will be modified */
    uint32_t srcChange = 0;
    uint32_t dstChange = 0;
    pread(pSrcFile->h, &srcChange, 4, 24);
    pread(pFile->h, &dstChange, 4, 24);
    
    /* copy the actual database */
    s = copyfile_state_alloc();
    lseek(pSrcFile->h, 0, SEEK_SET);
    lseek(pFile->h, 0, SEEK_SET);
    if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_DATA) ){
      int err=errno;
      switch(err) {
        case ENOMEM:
          rc = SQLITE_NOMEM;
          break;
        default:
          storeLastErrno(pFile, err);
          rc = SQLITE_IOERR;
      }
    }
    copyfile_state_free(s);
    
    if (srcChange == dstChange) {
      /* modify the change counter to force page zero to be reloaded */
      dstChange ++;
      pwrite(pFile->h, &dstChange, 4, 24);
    }
  }
  if( isSrcCorrupt ){
    sqlite3demo_superunlock_corrupt(src_file, corruptSrcFileLock);
  }else{
    /* done with the source db so end the transaction */
    sqlite3_exec(srcdb2, "COMMIT", 0, 0, 0);
  }
  /* zero out any old journal clutter */
  if( rc==SQLITE_OK ){
    int skipWAL = (srcWalFD<0)?0:1;
    unixInvalidateSupportFiles(pFile, skipWAL);
  }
  
end_replace_database:
  if( pSrcBtree ){
    sqlite3_close(srcdb2);
    sqlite3BtreeLeave(pSrcBtree);
  }
  sqlite3_mutex_leave(srcdb->mutex);
  if( isDstCorrupt ){
    sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
  }else{
    sqlite3demo_superunlock(pLock);
  }
  return rc;
}
#define SQLITE_FILE_HEADER_LEN 16
/* Check for a conflicting lock.  If one is found, print an this
 ** on standard output using the format string given and return 1.
 ** If there are no conflicting locks, return 0.
 */
static int unixIsLocked(
  pid_t pid,            /* PID to test for lock owner */
  int h,                /* File descriptor to check */
  int type,             /* F_RDLCK or F_WRLCK */
  unsigned int iOfst,   /* First byte of the lock */
  unsigned int iCnt,    /* Number of bytes in the lock range */
  const char *zType     /* Type of lock */
){
  struct flock lk;
  int err;
  
  memset(&lk, 0, sizeof(lk));
  lk.l_type = type;
  lk.l_whence = SEEK_SET;
  lk.l_start = iOfst;
  lk.l_len = iCnt;
  
  if( pid!=SQLITE_LOCKSTATE_ANYPID ){
#ifndef F_GETLKPID
# warning F_GETLKPID undefined, _sqlite3_lockstate falling back to F_GETLK
    err = fcntl(h, F_GETLK, &lk);
#else
    lk.l_pid = pid;
    err = fcntl(h, F_GETLKPID, &lk);
#endif
  }else{
    err = fcntl(h, F_GETLK, &lk);
  }
  
  if( err==(-1) ){
    fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno);
    return -1;
  }
  
  if( lk.l_type!=F_UNLCK && (pid==SQLITE_LOCKSTATE_ANYPID || lk.l_pid==pid) ){
#ifdef SQLITE_DEBUG
    fprintf(stderr, "%s lock held by %d\n", zType, (int)lk.l_pid);
#endif
    return 1;
  } 
  return 0;
}

static int unixLockstatePid(unixFile *, pid_t, int *);

#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */


/*
** If *pArg is initially negative then this is a query.  Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
**
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
*/
................................................................................
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
    case SQLITE_FCNTL_SET_LOCKPROXYFILE:
    case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
      return proxyFileControl(id,op,pArg);
    }
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
    case SQLITE_FCNTL_TRUNCATE_DATABASE: {
      return unixTruncateDatabase(pFile, (pArg ? (*(int *)pArg) : 0));
    }
    case SQLITE_FCNTL_REPLACE_DATABASE: {
      return unixReplaceDatabase(pFile, (sqlite3 *)pArg);
    }
    case SQLITE_FCNTL_LOCKSTATE_PID: {
      LockstatePID *pLockstate;
      int rc;
      
      if( pArg==NULL ){
        return SQLITE_MISUSE;
      }
      pLockstate = (LockstatePID *)pArg;
      rc = unixLockstatePid(pFile, pLockstate->pid, &(pLockstate->state));
      return rc;
    }
      
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
  }
  return SQLITE_NOTFOUND;
}

/*
** If pFd->sectorSize is non-zero when this function is called, it is a
** no-op. Otherwise, the values of pFd->sectorSize and 
................................................................................
  if( rc==SQLITE_OK ){
    assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK );
    rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
  }
  return rc;
}

#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
static const char *proxySharedMemoryBasePath(unixFile *);
#endif

/*
** Open a shared-memory area associated with open database file pDbFd.  
** This particular implementation uses mmapped files.
**
** The file used to implement shared-memory is in the same directory
** as the open database file and has the same name as the open database
** file with the "-shm" suffix added.  For example, if the database file
................................................................................
#endif

    /* Call fstat() to figure out the permissions on the database file. If
    ** a new *-shm file is created, an attempt will be made to create it
    ** with the same permissions.
    */
    if( osFstat(pDbFd->h, &sStat) ){
      storeLastErrno(pDbFd, errno);
      rc = SQLITE_IOERR_FSTAT;
      goto shm_open_err;
    }

#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE \
      && !defined(SQLITE_SHM_DIRECTORY)
    /* If pDbFd is configured with proxy locking mode, use the local 
    ** lock file path to determine the -shm file path
    */
    if( isProxyLockingMode(pDbFd) ){
      zBasePath = proxySharedMemoryBasePath(pDbFd);
      if( !zBasePath ){
        rc = SQLITE_CANTOPEN_BKPT;
        goto shm_open_err;
      }
    }
#endif
    
#ifdef SQLITE_SHM_DIRECTORY
    nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31;
#else
    nShmFilename = 6 + (int)strlen(zBasePath);
#endif
    pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
    if( pShmNode==0 ){
................................................................................
      if( pShmNode->pShmMutex==0 ){
        rc = SQLITE_NOMEM_BKPT;
        goto shm_open_err;
      }
    }

    if( pInode->bProcessLock==0 ){
#ifdef __APPLE__
      /* On MacOS and iOS, avoid even trying to open a read-only SHM file
      ** for writing, because doing so generates scary log messages */
      if( osAccess(zShm, R_OK|W_OK)!=0 && (errno==EPERM || errno==EACCES) ){
        pShmNode->hShm = -1;
      }else
#endif
      if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
        pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW,
                                     (sStat.st_mode&0777));
      }
      if( pShmNode->hShm<0 ){
        pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW,
                                     (sStat.st_mode&0777));
................................................................................
  /* If pShmNode->nRef has reached 0, then close the underlying
  ** shared-memory file, too */
  assert( unixFileMutexNotheld(pDbFd) );
  unixEnterMutex();
  assert( pShmNode->nRef>0 );
  pShmNode->nRef--;
  if( pShmNode->nRef==0 ){
    if( deleteFlag && pShmNode->hShm>=0 ) {
      if (deleteFlag == 1) { 
        osUnlink(pShmNode->zFilename);
      } else if (deleteFlag == 2) {
        /* ftruncate(pShmNode->hShm, 32 * 1024); */
      }
    }
    unixShmPurge(pDbFd);
  }
  unixLeaveMutex();

  return SQLITE_OK;
}
................................................................................
#else
# define unixShmMap     0
# define unixShmLock    0
# define unixShmBarrier 0
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
static const char *unixTempFileDir(void);

static int unixInvalidateSupportFiles(unixFile *pFile, int skipWAL) {
  char jPath[MAXPATHLEN+9];
  int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
  if( zLen<MAXPATHLEN ){
    size_t jLen;
    const char extensions[3][9] = { "-wal", "-journal", "-shm" };
    int j = (skipWAL ? 1 : 0);
    for( ; j<3; j++ ){
      
      /* Check to see if the shm file is already opened for this pFile */
      if( j==2 ){
        unixEnterMutex(); /* Because pFile->pInode is shared across threads */
        unixShmNode *pShmNode = pFile->pInode->pShmNode;
        if( pShmNode && !pShmNode->isReadonly ){
          struct stat sStat;
          sqlite3_mutex_enter(pShmNode->pShmMutex);
          
          if( pShmNode->hShm>=0 && !osFstat(pShmNode->hShm, &sStat) ){
            unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
            if( size>0 ){
              bzero(pShmNode->apRegion[0], size);
              sqlite3_mutex_leave(pShmNode->pShmMutex);
              unixLeaveMutex();
              continue;
            }
          }
          sqlite3_mutex_leave(pShmNode->pShmMutex);
        }
        unixLeaveMutex();
      }
      jLen = strlcpy(&jPath[zLen], extensions[j], 9);
      if( jLen < 9 ){
        int jflags = (j<2) ? O_TRUNC : O_RDWR;
        int jfd = open(jPath, jflags);
        if( jfd==(-1) ){
          if( errno!=ENOENT ){
            perror(jPath);
          }
        } else {
          if( j==2 ){
            struct stat sStat;
            if( !osFstat(jfd, &sStat) ){
              unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
              if( size>0 ){
                uint32_t zero = 0;
                pwrite(jfd, &zero, (size_t)size, 0);
              }
            }
          }
          fsync(jfd);
          close(jfd);
        }
      }
    }
  }
  return SQLITE_OK;
}

static int unixUnsafeTruncateDatabase(unixFile *pFile){
  /* this is nasty & bad.  destruction with prejudice.  we'll lose all the
  ** file locks in this process, however. sqlite3_file_control works properly.
  ** But if it fails, this works approximately
  */
  char journalPath[MAXPATHLEN];
  char walPath[MAXPATHLEN];
  int rc = SQLITE_OK;
  
#ifdef DEBUG
  fprintf(stderr, "Force truncating database %s\n", pFile->zPath);
#endif
  strlcpy(journalPath, pFile->zPath, MAXPATHLEN);
  strlcat(journalPath, "-journal", MAXPATHLEN);
  strlcpy(walPath, pFile->zPath, MAXPATHLEN);
  strlcat(walPath, "-wal", MAXPATHLEN);
  int fd1 = pFile->h;
  int result = 0;
  result = ftruncate(fd1, 0ll);
  if (result) {
    result = errno;
  }
  if (result) {
    rc = SQLITE_IOERR;
    storeLastErrno(pFile, result);
  }
  
  int fd2 = open(journalPath, O_RDWR);
  int result2 = 0;
  if (fd2 < 0) {
    if (errno != ENOENT) {
      result2 = errno;
    } else {
      result2 = 0;
    }
  } else {
    result2 = ftruncate(fd2, 0ll);
    if (result2) {
      result2 = errno;
    }
  }
  if (result2 && !result) {
    rc = SQLITE_IOERR;
    storeLastErrno(pFile, result2);
  }
  
  int fd3 = open(walPath, O_RDWR);
  int result3 = 0;
  if (fd3 < 0) {
    if (errno != ENOENT) {
      result3 = errno;
    } else {
      result3 = 0;
    }
  } else {
    result3 = ftruncate(fd3, 0ll);
    if (result3) {
      result3 = errno;
    }
  }
  if (result3 && !(result || result2)) {
    rc = SQLITE_IOERR;
    storeLastErrno(pFile, result2);
  }
  
  if (fd3 >= 0) {
    fsync(fd3);
    close(fd3);
  }
  if (fd2 >= 0) {
    fsync(fd2);
    close(fd2);
  }
  fsync(fd1);
	
  return rc;
}

static int unixTruncateDatabase(unixFile *pFile, int bFlags) {
  sqlite3_file *id = (sqlite3_file *)pFile;
  int rc = SQLITE_OK;
  void *pLock = NULL;
  int flags = 0;
  int corruptFileLock = 0;
  int isCorrupt = 0;
  int force = (bFlags & SQLITE_TRUNCATE_FORCE);
  int safeFailed = 0;

#if SQLITE_ENABLE_DATA_PROTECTION
  flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
  if( isProxyLockingMode(pFile) ){
    flags |= SQLITE_OPEN_AUTOPROXY;
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE,
                                         &corruptFileLock);
    }
    if( rc && !force ){
      return rc;
    }
    rc = SQLITE_OK; /* Ignore the locking failure if force is true */
  }
  if( (bFlags&SQLITE_TRUNCATE_INITIALIZE_HEADER_MASK)!=0 ){
    /* initialize a new database in TMPDIR and copy the contents over */
    const char *tDir = unixTempFileDir();
    int tDirLen = strlen(tDir);
    int tLen = sizeof(char) * (tDirLen + 12);
    char *tDbPath = (char *)malloc(tLen);
    int tFd = -1;
    
    strlcpy(tDbPath, tDir, tLen);
    if( tDbPath[(tDirLen-1)] != '/' ){
      strlcat(tDbPath, "/tmpdbXXXXX", tLen);
    } else {
      strlcat(tDbPath, "tmpdbXXXXX", tLen);
    }
    tFd = mkstemp(tDbPath);
    if( tFd==-1 ){
      storeLastErrno(pFile, errno);
      rc = SQLITE_IOERR;
      safeFailed = 1;
    }else{
      sqlite3 *tDb = NULL;
      copyfile_state_t s;
      int trc = sqlite3_open_v2(tDbPath, &tDb,
                   (SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
                      | SQLITE_OPEN_AUTOPROXY), NULL);
      char *errmsg = NULL;
      const char *sql = "";
      if( !trc && (bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) ){
        const char pagesize_sql[4][22] = {
          "pragma page_size=1024",
          "pragma page_size=2048",
          "pragma page_size=4096",
          "pragma page_size=8192" 
        };
        int iPagesize = (((bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) >> 4) - 1);
        assert( iPagesize>=0 && iPagesize<=4 );
        sql = pagesize_sql[iPagesize];
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
      }
      if( !trc ){
        const char autovacuum_sql[3][21] = {
          "pragma auto_vacuum=0",
          "pragma auto_vacuum=1",
          "pragma auto_vacuum=2"
        };
        int iAutovacuum = 2; /* default to incremental */
        if( (bFlags&SQLITE_TRUNCATE_AUTOVACUUM_MASK) ){
          iAutovacuum = (((bFlags&SQLITE_TRUNCATE_AUTOVACUUM_MASK) >> 2) - 1);
        }
        assert( iAutovacuum>=0 && iAutovacuum<=2 );
        sql = autovacuum_sql[iAutovacuum];
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
      }
      if( !trc && (bFlags&SQLITE_TRUNCATE_JOURNALMODE_WAL) ){
        sql = "pragma journal_mode=wal";
        trc = sqlite3_exec(tDb, sql, 0, 0, &errmsg);
      }
      if( trc ){
        if( !tDb ){
          fprintf(stderr, "failed to open temp database '%s' to reset "
                          "truncated database %s with flags %x: %d\n",
                           tDbPath, pFile->zPath, bFlags, trc);
        }else{
          fprintf(stderr, "failed to set '%s' on truncated database %s, %d: "
                          "%s\n", sql, pFile->zPath, trc, errmsg);
        }
      }
      if( tDb ){
        int off = 0;
        /* merge the wal into the db */
        sqlite3_file_control(tDb, NULL, SQLITE_FCNTL_PERSIST_WAL, &off);
        sqlite3_close(tDb);
      }
      s = copyfile_state_alloc();
      lseek(tFd, 0, SEEK_SET);
      lseek(pFile->h, 0, SEEK_SET);
      if( fcopyfile(tFd, pFile->h, s, COPYFILE_DATA) ){
        int err=errno;
        switch(err) {
          case ENOMEM:
            trc = SQLITE_NOMEM;
            break;
          default:
            storeLastErrno(pFile, err);
            trc = SQLITE_IOERR;
        }
      }
      copyfile_state_free(s);
      fsync(pFile->h);
      close(tFd);
      unlink(tDbPath);
      if( trc!=SQLITE_OK ){
        safeFailed = 1;
        rc = trc;
      }
    }
    free(tDbPath);
  } else {
    rc = pFile->pMethod->xTruncate(id, 
           ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
    if( rc ){
      safeFailed = 1;
    }
  }
  if( rc==SQLITE_OK || force ){
    rc = unixInvalidateSupportFiles(pFile, 0);
    if( rc ){
      safeFailed = 1;
    }
  }
  pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);


  if( isCorrupt ){
    sqlite3demo_superunlock_corrupt(id, corruptFileLock);
  }else if( pLock ){
    sqlite3demo_superunlock(pLock);
  }else{
    assert(force);
  }
  
  if( force && safeFailed){
    rc = unixUnsafeTruncateDatabase(pFile);
  }
  
  return rc;
}

/*
 ** Lock locations for shared-memory locks used by WAL mode.
 */
#ifndef SHM_BASE
# define SHM_BASE          120
# define SHM_WRITE         SHM_BASE
# define SHM_CHECKPOINT    (SHM_BASE+1)
# define SHM_RECOVER       (SHM_BASE+2)
# define SHM_READ_FIRST    (SHM_BASE+3)
# define SHM_READ_SIZE     5
#endif /* SHM_BASE */

/*
** This test only works for lock testing on unix/posix VFS.
** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
*/
static int unixLockstatePid(unixFile *pFile, pid_t pid, int *pLockstate){
  int hDb;        /* File descriptor for the open database file */
  int hShm = -1;  /* File descriptor for WAL shared-memory file */
  ssize_t got;    /* Bytes read from header */
  int isWal = 0;             /* True if in WAL mode */
  int nLock = 0;             /* Number of locks held */
  int noHdr = 0;             /* Zero byte DB has no header */
  unsigned char aHdr[100];   /* Database header */
  
  assert(pLockstate);
  
  /* make sure we are dealing with a database file */
  hDb = pFile->h;
  if( hDb<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
  got = pread(hDb, aHdr, 100, 0);
  if( got<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  if( got==0 ){
    noHdr = 1;
  }else if( got!=100
         || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0
  ){
    *pLockstate = SQLITE_LOCKSTATE_NOTADB;
    return SQLITE_NOTADB;
  }
  
  /* First check for an exclusive lock */
  nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE,
                        "EXCLUSIVE");
  if (!noHdr) {
    isWal = aHdr[18]==2;
  }
  if( nLock==0 && isWal==0 ){
    /* Rollback mode */
    nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2,
                          "PENDING|RESERVED|SHARED");
  }
  if( nLock==0 && isWal!=0 ){
    /* lookup the file descriptor for the shared memory file if we have it open
    ** in this process */
    unixEnterMutex(); /* Because pFile->pInode is shared across threads */
    unixShmNode *pShmNode = pFile->pInode->pShmNode;
    if( pShmNode ){
      sqlite3_mutex_enter(pShmNode->pShmMutex);
      
      hShm = pShmNode->hShm;
      if( hShm >= 0){
        if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
           unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
          nLock = 1;
        }
      }
      
      sqlite3_mutex_leave(pShmNode->pShmMutex);
    } 
    
    if( hShm<0 ){
      /* the shared memory file isn't open in this process space, open our
      ** own FD */
      char zShm[MAXPATHLEN];
      
      /* WAL mode */
      strlcpy(zShm, pFile->zPath, MAXPATHLEN);
      strlcat(zShm, "-shm", MAXPATHLEN);
      hShm = open(zShm, O_RDONLY, 0);
      if( hShm<0 ){
        *pLockstate = SQLITE_LOCKSTATE_OFF;
        unixLeaveMutex();
        return SQLITE_OK;
      }
      if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
         unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
        nLock = 1;
      }
      close(hShm);
    }
    unixLeaveMutex();
  }
  if( nLock>0 ){
    *pLockstate = SQLITE_LOCKSTATE_ON;
  } else {
    *pLockstate = SQLITE_LOCKSTATE_OFF;
  }
  return SQLITE_OK;
}

#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */

#if SQLITE_MAX_MMAP_SIZE>0
/*
** If it is currently memory mapped, unmap file pFd.
*/
static void unixUnmapfile(unixFile *pFd){
  assert( pFd->nFetchOut==0 );
  if( pFd->pMapRegion ){
................................................................................
static int proxyClose(sqlite3_file*);
static int proxyLock(sqlite3_file*, int);
static int proxyUnlock(sqlite3_file*, int);
static int proxyCheckReservedLock(sqlite3_file*, int*);
IOMETHODS(
  proxyIoFinder,            /* Finder function name */
  proxyIoMethods,           /* sqlite3_io_methods object name */
  2,                        /* shared memory is enabled */
  proxyClose,               /* xClose method */
  proxyLock,                /* xLock method */
  proxyUnlock,              /* xUnlock method */
  proxyCheckReservedLock,   /* xCheckReservedLock method */
  0                         /* xShmMap method */
)
#endif
................................................................................
#endif
  }

  if( pLockingStyle == &posixIoMethods
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
    || pLockingStyle == &nfsIoMethods
#endif
     /* support WAL mode on read only mounted filesystem */
    || (pLockingStyle == &nolockIoMethods && zFilename!=0)
  ){
    unixEnterMutex();
    rc = findInodeInfo(pNew, &pNew->pInode);
    if( rc!=SQLITE_OK ){
      /* If an error occurred in findInodeInfo(), close the file descriptor
      ** immediately, before releasing the mutex. findInodeInfo() may fail
      ** in two scenarios:
................................................................................
  sqlite3_file *pFile,         /* The file descriptor to be filled in */
  int flags,                   /* Input flags to control the opening */
  int *pOutFlags               /* Output flags returned to SQLite core */
){
  unixFile *p = (unixFile *)pFile;
  int fd = -1;                   /* File descriptor returned by open() */
  int openFlags = 0;             /* Flags to pass to open() */
#if SQLITE_ENABLE_DATA_PROTECTION
  int eType = flags&0xFE0FFF00;  /* Type of file to open */
#else
  int eType = flags&0xFEFFFF00;  /* Type of file to open */
#endif
  int noLock;                    /* True to omit locking primitives */
  int rc = SQLITE_OK;            /* Function Return Code */
  int ctrlFlags = 0;             /* UNIXFILE_* flags */

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);
................................................................................
  ** 'conch file' locking functions later on.  */
  if( isReadonly )  openFlags |= O_RDONLY;
  if( isReadWrite ) openFlags |= O_RDWR;
  if( isCreate )    openFlags |= O_CREAT;
  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW);

#if SQLITE_ENABLE_DATA_PROTECTION
  p->protFlags = (flags & SQLITE_OPEN_FILEPROTECTION_MASK);
#endif
    
  if( fd<0 ){
    mode_t openMode;              /* Permissions to create file with */
    uid_t uid;                    /* Userid for the file */
    gid_t gid;                    /* Groupid for the file */
    rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
    if( rc!=SQLITE_OK ){
      assert( !p->pPreallocatedUnused );
................................................................................
      robust_close(p, fd, __LINE__);
      return SQLITE_NOMEM_BKPT;
    }
#else
    osUnlink(zName);
#endif
  }
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  else{
    p->openFlags = openFlags;
  }
#endif
  
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
  if( fstatfs(fd, &fsInfo) == -1 ){
................................................................................
  /* Set up appropriate ctrlFlags */
  if( isDelete )                ctrlFlags |= UNIXFILE_DELETE;
  if( isReadonly )              ctrlFlags |= UNIXFILE_RDONLY;
  noLock = eType!=SQLITE_OPEN_MAIN_DB;
  if( noLock )                  ctrlFlags |= UNIXFILE_NOLOCK;
  if( isNewJrnl )               ctrlFlags |= UNIXFILE_DIRSYNC;
  if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
#if defined(SQLITE_ENABLE_PERSIST_WAL)
  if( eType==SQLITE_OPEN_MAIN_DB ) {
    ctrlFlags |= UNIXFILE_PERSIST_WAL;
  }
#endif

#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
  isAutoProxy = 1;
#endif
  if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
    char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
................................................................................
      useProxy = atoi(envforce)>0;
    }else{
      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
    }
    if( useProxy ){
      rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
      if( rc==SQLITE_OK ){
        /* cache the pMethod in case the transform fails */
        const struct sqlite3_io_methods *pMethod = pFile->pMethods;
        rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
        if( rc!=SQLITE_OK ){
          /* Use unixClose to clean up the resources added in fillInUnixFile 
          ** and clear all the structure's references.  Specifically, 
          ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op 
          */
          if( pMethod!=NULL ){
            pMethod->xClose(pFile);
          }else{
            unixClose(pFile);
          }
          return rc;
        }
      }
      goto open_finished;
    }
  }
#endif
................................................................................
  if( (dirSync & 1)!=0 ){
    int fd;
    rc = osOpenDirectory(zPath, &fd);
    if( rc==SQLITE_OK ){
      if( full_fsync(fd,0,0) ){
        rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
      }
#if OSCLOSE_CHECK_CLOSE_IOERR
      if( close(fd)&&!rc ){
        rc = SQLITE_IOERR_DIR_CLOSE;
      }
#else
      robust_close(0, fd, __LINE__);
#endif
    }else{
      assert( rc==SQLITE_CANTOPEN );
      rc = SQLITE_OK;
    }
  }
#endif
  return rc;
................................................................................
    }
    buf[i] = lockPath[i];
  }
  OSTRACE(("CREATELOCKPATH  proxy lock path=%s pid=%d\n",lockPath,osGetpid(0)));
  return 0;
}

#if SQLITE_ENABLE_LOCKING_STYLE
static int isProxyLockingMode(unixFile *pFile) {
  return (pFile->pMethod == &proxyIoMethods) ? 1 : 0;
}
#endif

#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
/*
** Return the shared memory base path based on the lock proxy file if the 
** lock proxy file is hosted on a shared memory compatible FS
*/
static const char *proxySharedMemoryBasePath(unixFile *pFile) {
  proxyLockingContext *pCtx;
  unixFile *pLockFile;
  
  assert(pFile!=NULL && pFile->lockingContext!=NULL);
  assert(pFile->pMethod == &proxyIoMethods);
  pCtx = ((proxyLockingContext *)(pFile->lockingContext));
  pLockFile = pCtx->lockProxy;
  if( pLockFile->pMethod->iVersion>=2 && pLockFile->pMethod->xShmMap!=0 ){
    return pCtx->lockProxyPath;
  }
  return NULL;
}
#endif

/*
** Create a new VFS file descriptor (stored in memory obtained from
** sqlite3_malloc) and open the file named "path" in the file descriptor.
**
** The caller is responsible not only for closing the file descriptor
** but also for freeing the memory associated with the file descriptor.
*/
................................................................................
  }
  if( fd<0 ){
    openFlags = O_RDONLY | O_NOFOLLOW;
    fd = robust_open(path, openFlags, 0);
    terrno = errno;
  }
  if( fd<0 ){
    sqlite3_free(pUnused);
    if( islockfile ){
      return SQLITE_BUSY;
    }
    switch (terrno) {
      case EACCES:
        return SQLITE_PERM;
      case EIO: 
................................................................................
/* Take the requested lock on the conch file and break a stale lock if the 
** host id matches.
*/
static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
  proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; 
  unixFile *conchFile = pCtx->conchFile;
  int rc = SQLITE_OK;

  struct timespec conchModTime;
  
  memset(&conchModTime, 0, sizeof(conchModTime));
  do {
    rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);

    if( rc==SQLITE_BUSY ){
      pCtx->nFails ++;
      /* If the lock failed (busy):
       * 1st try: get the mod time of the conch, wait 0.5s and try again. 
       * 2nd try: fail if the mod time changed or host id is different, wait 
       *           10 sec and try again
       * 3rd try: break the lock unless the mod time has changed.
       */
      struct stat buf;
      if( osFstat(conchFile->h, &buf) ){
        storeLastErrno(pFile, errno);
        return SQLITE_IOERR_LOCK;
      }
      
      if( pCtx->nFails==1 ){
        conchModTime = buf.st_mtimespec;
        usleep(500000); /* wait 0.5 sec and try the lock again*/
        continue;  
      }

      assert( pCtx->nFails>1 );
      if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || 
         conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
        return SQLITE_BUSY;
      }
      
      if( pCtx->nFails==2 ){  
        char tBuf[PROXY_MAXCONCHLEN];
        int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
        if( len<0 ){
          storeLastErrno(pFile, errno);
          return SQLITE_IOERR_LOCK;
        }
        if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
          /* don't break the lock if the host id doesn't match, but do log
           * an error to console so users can diagnose stale NFS locks more 
           * easily 
           */
          if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){
            uuid_t conchUUID;
            uuid_string_t conchUUIDString;
            uuid_string_t myUUIDString;
            assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
            memcpy(conchUUID, &tBuf[PROXY_HEADERLEN], PROXY_HOSTIDLEN);
            uuid_unparse(conchUUID, conchUUIDString);
            uuid_unparse(myHostID, myUUIDString);
            fprintf(stderr,
               "ERROR: sqlite database is locked because it is in use "
               "by another host that holds a host-exclusive lock on %s; "
               "this host (UUID %s) cannot override the host-exclusive lock "
               "until the other host (UUID %s) releases its locks on %s\n", 
               pFile->zPath, myUUIDString, conchUUIDString, conchFile->zPath);
            return SQLITE_BUSY;
          }
        }else{
          /* don't break the lock on short read or a version mismatch */
          return SQLITE_BUSY;
        }
        usleep(10000000); /* wait 10 sec and try the lock again */
        continue; 
      }
      
      assert( pCtx->nFails>=3 );
      if( (pCtx->nFails==3)&&(0==proxyBreakConchLock(pFile, myHostID)) ){
        rc = SQLITE_OK;
        if( lockType==EXCLUSIVE_LOCK ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
        }
        if( !rc ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
        }
      }
    }
  } while( rc==SQLITE_BUSY && pCtx->nFails<3 );
  
  return rc;
}

/* Takes the conch by taking a shared lock and read the contents conch, if 
** lockPath is non-NULL, the host ID and lock file path must match.  A NULL 
** lockPath means that the lockPath in the conch file will be used if the 
................................................................................
      conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
      
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        int fd;
        if( pFile->h>=0 ){
#if defined(STRICT_CLOSE_ERROR) && OSCLOSE_CHECK_CLOSE_IOERR
          if( close(pFile->h) ){
            storeLastErrno(pFile, errno);
            return SQLITE_IOERR_CLOSE;
          }
#else
          robust_close(pFile, pFile->h, __LINE__);
#endif
        }
        pFile->h = -1;
        fd = robust_open(pCtx->dbPath, pFile->openFlags, 0);
        OSTRACE(("TRANSPROXY: OPEN  %d\n", fd));
        if( fd>=0 ){
          pFile->h = fd;
        }else{
................................................................................
        pCtx->conchHeld = -1; /* read only FS/ lockless */
        rc = SQLITE_OK;
      }
    }
  }  
  if( rc==SQLITE_OK && lockPath ){
    pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
    if( pCtx->lockProxyPath==NULL ){
      rc = SQLITE_NOMEM;
    }
  }

  if( rc==SQLITE_OK ){
    pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
    if( pCtx->dbPath==NULL ){
      rc = SQLITE_NOMEM_BKPT;
    }
................................................................................
** This routine handles sqlite3_file_control() calls that are specific
** to proxy locking.
*/
static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
  switch( op ){
    case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
      unixFile *pFile = (unixFile*)id;
      if( isProxyLockingMode(pFile) ){
        proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
        proxyTakeConch(pFile);
        if( pCtx->lockProxyPath ){
          *(const char **)pArg = pCtx->lockProxyPath;
        }else{
          *(const char **)pArg = ":auto: (not held)";
        }
................................................................................
        *(const char **)pArg = NULL;
      }
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SET_LOCKPROXYFILE: {
      unixFile *pFile = (unixFile*)id;
      int rc = SQLITE_OK;
      int isProxyStyle = isProxyLockingMode(pFile);
      if( pArg==NULL || (const char *)pArg==0 ){
        if( isProxyStyle ){
          /* turn off proxy locking - not supported.  If support is added for
          ** switching proxy locking mode off then it will need to fail if
          ** the journal mode is WAL mode. 
          */
          rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;

Changes to src/os_win.c.

3539
3540
3541
3542
3543
3544
3545









3546
3547
3548
3549
3550
3551
3552
          }
        }
        OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
        return rc;
      }
      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
      return SQLITE_OK;









    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {







>
>
>
>
>
>
>
>
>







3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
          }
        }
        OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
        return rc;
      }
      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      int bPersist = *(int*)pArg;
      if( bPersist<0 ){
        *(int*)pArg = pFile->bPersistWal;
      }else{
        pFile->bPersistWal = bPersist!=0;
      }
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {

Changes to src/pager.c.

2578
2579
2580
2581
2582
2583
2584




2585
2586
2587
2588
2589
2590
2591
2592
....
2615
2616
2617
2618
2619
2620
2621




2622
2623
2624
2625
2626
2627
2628
2629
....
3688
3689
3690
3691
3692
3693
3694




3695
3696
3697
3698
3699
3700
3701
3702
....
5180
5181
5182
5183
5184
5185
5186




5187
5188
5189
5190
5191
5192
5193
5194
....
5320
5321
5322
5323
5324
5325
5326




5327
5328
5329
5330
5331
5332
5333
5334
....
5830
5831
5832
5833
5834
5835
5836



5837
5838
5839
5840
5841
5842
5843
....
7068
7069
7070
7071
7072
7073
7074












7075
7076
7077
7078
7079
7080
7081
....
7602
7603
7604
7605
7606
7607
7608

7609



7610
7611
7612

7613
7614
7615
7616
7617
7618
7619
....
7699
7700
7701
7702
7703
7704
7705







7706
7707
7708
7709
7710
7711
7712
  ** If successful, open the master journal file for reading.
  */
  pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
  pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
  if( !pMaster ){
    rc = SQLITE_NOMEM_BKPT;
  }else{




    const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
    rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
  }
  if( rc!=SQLITE_OK ) goto delmaster_out;

  /* Load the entire master journal file into space obtained from
  ** sqlite3_malloc() and pointed to by zMasterJournal.   Also obtain
  ** sufficient space (in zMasterPtr) to hold the names of master
................................................................................
    }
    if( exists ){
      /* One of the journals pointed to by the master journal exists.
      ** Open it and check if it points at the master journal. If
      ** so, return without deleting the master journal file.
      */
      int c;




      int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
      rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
      if( rc!=SQLITE_OK ){
        goto delmaster_out;
      }

      rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
      sqlite3OsClose(pJournal);
................................................................................
){
  int rc;               /* Return code */

#ifdef SQLITE_TEST
  sqlite3_opentemp_count++;  /* Used for testing and analysis only */
#endif





  vfsFlags |=  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
            SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
  rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0);
  assert( rc!=SQLITE_OK || isOpen(pFile) );
  return rc;
}

/*
................................................................................
          /* The journal file exists and no other connection has a reserved
          ** or greater lock on the database file. Now check that there is
          ** at least one non-zero bytes at the start of the journal file.
          ** If there is, then we consider this journal to be hot. If not, 
          ** it can be ignored.
          */
          if( !jrnlOpen ){




            int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
            rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
          }
          if( rc==SQLITE_OK ){
            u8 first = 0;
            rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
            if( rc==SQLITE_IOERR_SHORT_READ ){
              rc = SQLITE_OK;
................................................................................
      if( !isOpen(pPager->jfd) ){
        sqlite3_vfs * const pVfs = pPager->pVfs;
        int bExists;              /* True if journal file exists */
        rc = sqlite3OsAccess(
            pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
        if( rc==SQLITE_OK && bExists ){
          int fout = 0;




          int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
          assert( !pPager->tempFile );
          rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
          assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
          if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
            rc = SQLITE_CANTOPEN_BKPT;
            sqlite3OsClose(pPager->jfd);
          }
................................................................................
    if( !isOpen(pPager->jfd) ){
      if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
        sqlite3MemJournalOpen(pPager->jfd);
      }else{
        int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
        int nSpill;




        if( pPager->tempFile ){
          flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
          nSpill = sqlite3Config.nStmtSpill;
        }else{
          flags |= SQLITE_OPEN_MAIN_JOURNAL;
          nSpill = jrnlBufferSize(pPager);
        }
................................................................................
** Return the file handle for the database file associated
** with the pager.  This might return NULL if the file has
** not yet been opened.
*/
sqlite3_file *sqlite3PagerFile(Pager *pPager){
  return pPager->fd;
}













#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/*
** Reset the lock timeout for pager.
*/
void sqlite3PagerResetLockTimeout(Pager *pPager){
  int x = 0;
................................................................................
    rc = pagerExclusiveLock(pPager);
  }

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  if( rc==SQLITE_OK ){

    rc = sqlite3WalOpen(pPager->pVfs,



        pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, &pPager->pWal
    );

  }
  pagerFixMaplimit(pPager);

  return rc;
}


................................................................................
  if( rc==SQLITE_OK && pPager->pWal ){
    rc = pagerExclusiveLock(pPager);
    if( rc==SQLITE_OK ){
      rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
                           pPager->pageSize, (u8*)pPager->pTmpSpace);
      pPager->pWal = 0;
      pagerFixMaplimit(pPager);







      if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
    }
  }
  return rc;
}









>
>
>
>
|







 







>
>
>
>
|







 







>
>
>
>
|







 







>
>
>
>
|







 







>
>
>
>
|







 







>
>
>







 







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







 







>
|
>
>
>
|
|
<
>







 







>
>
>
>
>
>
>







2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
....
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
....
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
....
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
....
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
....
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
....
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
....
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650

7651
7652
7653
7654
7655
7656
7657
7658
....
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
  ** If successful, open the master journal file for reading.
  */
  pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
  pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
  if( !pMaster ){
    rc = SQLITE_NOMEM_BKPT;
  }else{
    const int flags = 
#if SQLITE_ENABLE_DATA_PROTECTION
      (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
      (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
    rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
  }
  if( rc!=SQLITE_OK ) goto delmaster_out;

  /* Load the entire master journal file into space obtained from
  ** sqlite3_malloc() and pointed to by zMasterJournal.   Also obtain
  ** sufficient space (in zMasterPtr) to hold the names of master
................................................................................
    }
    if( exists ){
      /* One of the journals pointed to by the master journal exists.
      ** Open it and check if it points at the master journal. If
      ** so, return without deleting the master journal file.
      */
      int c;
      int flags = 
#if SQLITE_ENABLE_DATA_PROTECTION
        (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
        (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
      rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
      if( rc!=SQLITE_OK ){
        goto delmaster_out;
      }

      rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
      sqlite3OsClose(pJournal);
................................................................................
){
  int rc;               /* Return code */

#ifdef SQLITE_TEST
  sqlite3_opentemp_count++;  /* Used for testing and analysis only */
#endif

  vfsFlags |=  
#if SQLITE_ENABLE_DATA_PROTECTION
            (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
            SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
  rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0);
  assert( rc!=SQLITE_OK || isOpen(pFile) );
  return rc;
}

/*
................................................................................
          /* The journal file exists and no other connection has a reserved
          ** or greater lock on the database file. Now check that there is
          ** at least one non-zero bytes at the start of the journal file.
          ** If there is, then we consider this journal to be hot. If not, 
          ** it can be ignored.
          */
          if( !jrnlOpen ){
            int f = 
#if SQLITE_ENABLE_DATA_PROTECTION
              (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
              SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
            rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
          }
          if( rc==SQLITE_OK ){
            u8 first = 0;
            rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
            if( rc==SQLITE_IOERR_SHORT_READ ){
              rc = SQLITE_OK;
................................................................................
      if( !isOpen(pPager->jfd) ){
        sqlite3_vfs * const pVfs = pPager->pVfs;
        int bExists;              /* True if journal file exists */
        rc = sqlite3OsAccess(
            pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
        if( rc==SQLITE_OK && bExists ){
          int fout = 0;
          int f = 
#if SQLITE_ENABLE_DATA_PROTECTION
            (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
            SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
          assert( !pPager->tempFile );
          rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
          assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
          if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
            rc = SQLITE_CANTOPEN_BKPT;
            sqlite3OsClose(pPager->jfd);
          }
................................................................................
    if( !isOpen(pPager->jfd) ){
      if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
        sqlite3MemJournalOpen(pPager->jfd);
      }else{
        int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
        int nSpill;

#if SQLITE_ENABLE_DATA_PROTECTION
        flags |= (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK);
#endif
        if( pPager->tempFile ){
          flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
          nSpill = sqlite3Config.nStmtSpill;
        }else{
          flags |= SQLITE_OPEN_MAIN_JOURNAL;
          nSpill = jrnlBufferSize(pPager);
        }
................................................................................
** Return the file handle for the database file associated
** with the pager.  This might return NULL if the file has
** not yet been opened.
*/
sqlite3_file *sqlite3PagerFile(Pager *pPager){
  return pPager->fd;
}

#if !defined(SQLITE_OMIT_WAL)
/*
 ** Return the file handle for the WAL journal file associated
 ** with the pager.  This might return NULL if the file has
 ** not yet been opened.
 */
sqlite3_file *sqlite3PagerWalFile(Pager *pPager){
  return ((pPager->pWal) ? sqlite3WalFile(pPager->pWal) : (NULL));
}
#endif


#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/*
** Reset the lock timeout for pager.
*/
void sqlite3PagerResetLockTimeout(Pager *pPager){
  int x = 0;
................................................................................
    rc = pagerExclusiveLock(pPager);
  }

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  if( rc==SQLITE_OK ){
#if SQLITE_ENABLE_DATA_PROTECTION
    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, (pPager->vfsFlags & (SQLITE_OPEN_FILEPROTECTION_MASK | SQLITE_OPEN_READONLY)), 
        &pPager->pWal);
#else
    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, (pPager->vfsFlags & SQLITE_OPEN_READONLY), &pPager->pWal);

#endif
  }
  pagerFixMaplimit(pPager);

  return rc;
}


................................................................................
  if( rc==SQLITE_OK && pPager->pWal ){
    rc = pagerExclusiveLock(pPager);
    if( rc==SQLITE_OK ){
      rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
                           pPager->pageSize, (u8*)pPager->pTmpSpace);
      pPager->pWal = 0;
      pagerFixMaplimit(pPager);

      /* Ensure that the WAL file is deleted even if the PERSIST_WAL
      ** hint is enabled. */
      if( rc==SQLITE_OK ){
        rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
        if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
      }
      if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
    }
  }
  return rc;
}


Changes to src/pager.h.

202
203
204
205
206
207
208

209
210
211
212
213
214
215
#ifdef SQLITE_DEBUG
  int sqlite3PagerRefcount(Pager*);
#endif
int sqlite3PagerMemUsed(Pager*);
const char *sqlite3PagerFilename(const Pager*, int);
sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);

sqlite3_file *sqlite3PagerJrnlFile(Pager*);
const char *sqlite3PagerJournalname(Pager*);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager*);
int sqlite3SectorSize(sqlite3_file *);







>







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#ifdef SQLITE_DEBUG
  int sqlite3PagerRefcount(Pager*);
#endif
int sqlite3PagerMemUsed(Pager*);
const char *sqlite3PagerFilename(const Pager*, int);
sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);
sqlite3_file *sqlite3PagerWalFile(Pager *pPager);
sqlite3_file *sqlite3PagerJrnlFile(Pager*);
const char *sqlite3PagerJournalname(Pager*);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager*);
int sqlite3SectorSize(sqlite3_file *);

Changes to src/pcache1.c.

382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
    assert( pcache1.nFreeSlot<=pcache1.nSlot );
    sqlite3_mutex_leave(pcache1.mutex);
  }else{
    assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
    sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
    {
      int nFreed = 0;
      nFreed = sqlite3MallocSize(p);
      sqlite3_mutex_enter(pcache1.mutex);
      sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
      sqlite3_mutex_leave(pcache1.mutex);
    }
#endif
    sqlite3_free(p);
  }







<
|







382
383
384
385
386
387
388

389
390
391
392
393
394
395
396
    assert( pcache1.nFreeSlot<=pcache1.nSlot );
    sqlite3_mutex_leave(pcache1.mutex);
  }else{
    assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
    sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
    {

      int nFreed = sqlite3MallocSize(p);
      sqlite3_mutex_enter(pcache1.mutex);
      sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
      sqlite3_mutex_leave(pcache1.mutex);
    }
#endif
    sqlite3_free(p);
  }

Changes to src/pragma.c.

213
214
215
216
217
218
219
220
221
222
223

224
225
226
227
228
229
230
231
    Db *pDb = db->aDb;
    int n = db->nDb;
    assert( SQLITE_FullFSync==PAGER_FULLFSYNC );
    assert( SQLITE_CkptFullFSync==PAGER_CKPT_FULLFSYNC );
    assert( SQLITE_CacheSpill==PAGER_CACHESPILL );
    assert( (PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL)
             ==  PAGER_FLAGS_MASK );
    assert( (pDb->safety_level & PAGER_SYNCHRONOUS_MASK)==pDb->safety_level );
    while( (n--) > 0 ){
      if( pDb->pBt ){
        sqlite3BtreeSetPagerFlags(pDb->pBt,

                 pDb->safety_level | (db->flags & PAGER_FLAGS_MASK) );
      }
      pDb++;
    }
  }
}
#else
# define setAllPagerFlags(X)  /* no-op */







<



>
|







213
214
215
216
217
218
219

220
221
222
223
224
225
226
227
228
229
230
231
    Db *pDb = db->aDb;
    int n = db->nDb;
    assert( SQLITE_FullFSync==PAGER_FULLFSYNC );
    assert( SQLITE_CkptFullFSync==PAGER_CKPT_FULLFSYNC );
    assert( SQLITE_CacheSpill==PAGER_CACHESPILL );
    assert( (PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL)
             ==  PAGER_FLAGS_MASK );

    while( (n--) > 0 ){
      if( pDb->pBt ){
        sqlite3BtreeSetPagerFlags(pDb->pBt,
                 (pDb->safety_level & PAGER_SYNCHRONOUS_MASK)
                   | (db->flags & PAGER_FLAGS_MASK) );
      }
      pDb++;
    }
  }
}
#else
# define setAllPagerFlags(X)  /* no-op */

Changes to src/prepare.c.

10
11
12
13
14
15
16



17
18
19
20
21
22
23
...
775
776
777
778
779
780
781



782
783
784
785
786
787
788
...
815
816
817
818
819
820
821



822
823
824
825
826
827
828
...
858
859
860
861
862
863
864
865


866
867
868
869
870
871
872
**
*************************************************************************
** This file contains the implementation of the sqlite3_prepare()
** interface, and routines that contribute to loading the database schema
** from disk.
*/
#include "sqliteInt.h"




/*
** Fill the InitData structure with an error message that indicates
** that the database is corrupt.
*/
static void corruptSchema(
  InitData *pData,     /* Initialization context */
................................................................................
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
){
  int rc;
  rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail);



  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
  return rc;
}
int sqlite3_prepare_v2(
  sqlite3 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
................................................................................
  ** SQLITE_PREPARE_* flags.
  **
  ** Proof by comparison to the implementation of sqlite3_prepare_v2()
  ** directly above. */
  rc = sqlite3LockAndPrepare(db,zSql,nBytes,
                 SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
                 0,ppStmt,pzTail);



  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
  return rc;
}


#ifndef SQLITE_OMIT_UTF16
/*
................................................................................
    nBytes = sz;
  }
  sqlite3_mutex_enter(db->mutex);
  zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
  if( zSql8 ){
    rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
  }



  if( zTail8 && pzTail ){
    /* If sqlite3_prepare returns a tail pointer, we calculate the
    ** equivalent pointer into the UTF-16 string by counting the unicode
    ** characters between zSql8 and zTail8, and then returning a pointer
    ** the same number of characters into the UTF-16 string.
    */
    int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));







>
>
>







 







>
>
>







 







>
>
>







 







|
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
...
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
**
*************************************************************************
** This file contains the implementation of the sqlite3_prepare()
** interface, and routines that contribute to loading the database schema
** from disk.
*/
#include "sqliteInt.h"
#ifdef SQLITE_ENABLE_SQLRR
# include "sqlrr.h"
#endif

/*
** Fill the InitData structure with an error message that indicates
** that the database is corrupt.
*/
static void corruptSchema(
  InitData *pData,     /* Initialization context */
................................................................................
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
){
  int rc;
  rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail);
#ifdef SQLITE_ENABLE_SQLRR
  SRRecPrepare(db, zSql, nBytes, 0, *ppStmt);
#endif
  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
  return rc;
}
int sqlite3_prepare_v2(
  sqlite3 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
................................................................................
  ** SQLITE_PREPARE_* flags.
  **
  ** Proof by comparison to the implementation of sqlite3_prepare_v2()
  ** directly above. */
  rc = sqlite3LockAndPrepare(db,zSql,nBytes,
                 SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
                 0,ppStmt,pzTail);
#ifdef SQLITE_ENABLE_SQLRR
  SRRecPrepare(db, zSql, nBytes, 1, *ppStmt);
#endif
  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
  return rc;
}


#ifndef SQLITE_OMIT_UTF16
/*
................................................................................
    nBytes = sz;
  }
  sqlite3_mutex_enter(db->mutex);
  zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
  if( zSql8 ){
    rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
  }
#ifdef SQLITE_ENABLE_SQLRR
  SRRecPrepare(db, zSql8, -1, 1, *ppStmt);
#endif
  if( zTail8 && pzTail ){
    /* If sqlite3_prepare returns a tail pointer, we calculate the
    ** equivalent pointer into the UTF-16 string by counting the unicode
    ** characters between zSql8 and zTail8, and then returning a pointer
    ** the same number of characters into the UTF-16 string.
    */
    int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));

Changes to src/sqlite.h.in.

567
568
569
570
571
572
573


574
575
576
577
578
579
580
581
582
#define SQLITE_OPEN_SUBJOURNAL       0x00002000  /* VFS only */
#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */
#define SQLITE_OPEN_NOMUTEX          0x00008000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */


#define SQLITE_OPEN_NOFOLLOW         0x01000000  /* Ok for sqlite3_open_v2() */

/* Reserved:                         0x00F00000 */

/*
** CAPI3REF: Device Characteristics
**
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
** object returns an integer which is a vector of these







>
>

<







567
568
569
570
571
572
573
574
575
576

577
578
579
580
581
582
583
#define SQLITE_OPEN_SUBJOURNAL       0x00002000  /* VFS only */
#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */
#define SQLITE_OPEN_NOMUTEX          0x00008000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */
#define SQLITE_OPEN_FILEPROTECTION_MASK \
                                     0x00700000
#define SQLITE_OPEN_NOFOLLOW         0x01000000  /* Ok for sqlite3_open_v2() */

/* Reserved:                         0x00F00000 */

/*
** CAPI3REF: Device Characteristics
**
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
** object returns an integer which is a vector of these

Added src/sqlite3_private.h.

































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
 *  sqlite3_private.h
 */

#ifndef _SQLITE3_PRIVATE_H
#define _SQLITE3_PRIVATE_H

#ifdef __cplusplus
extern "C" {
#endif

#define SQLITE_LOCKSTATE_OFF    0
#define SQLITE_LOCKSTATE_ON     1
#define SQLITE_LOCKSTATE_NOTADB 2
#define SQLITE_LOCKSTATE_ERROR  -1

#define SQLITE_LOCKSTATE_ANYPID -1

/* 
** Test a file path for sqlite locks held by a process ID (-1 = any PID). 
** Returns one of the following integer codes:
** 
**   SQLITE_LOCKSTATE_OFF    no active sqlite file locks match the specified pid
**   SQLITE_LOCKSTATE_ON     active sqlite file locks match the specified pid
**   SQLITE_LOCKSTATE_NOTADB path points to a file that is not an sqlite db file
**   SQLITE_LOCKSTATE_ERROR  path was not vaild or was unreadable
**
** There is no support for identifying db files encrypted via SEE encryption
** currently.  Zero byte files are tested for sqlite locks, but if no sqlite 
** locks are present then SQLITE_LOCKSTATE_NOTADB is returned.
*/
extern int _sqlite3_lockstate(const char *path, pid_t pid);

/*
** Test an open database connection for sqlite locks held by a process ID,
** if a process has an open database connection this will avoid trashing file
** locks by re-using open file descriptors for the database file and support
** files (-shm)
*/
#define SQLITE_FCNTL_LOCKSTATE_PID          103

/*
** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control() 
** to truncate a database and its associated journal file to zero length.  The 
** SQLITE_TRUNCATE_* flags represent optional flags to safely initialize an
** empty database in the place of the truncated database, the flags are passed 
** into sqlite3_file_control via the fourth argument using a pointer to an integer
** configured with the ORed flags.  If the fourth argument is NULL, the default 
** behavior is applied and the database file is truncated to zero bytes, a rollback 
** journal (if present) is unlinked, a WAL journal (if present) is truncated to zero 
** bytes and the first few bytes of the -shm file is scrambled to trigger existing
** connections to rebuild the index from the database file contents.
*/
#define SQLITE_FCNTL_TRUNCATE_DATABASE      101
#define SQLITE_TRUNCATE_DATABASE            SQLITE_FCNTL_TRUNCATE_DATABASE
#define SQLITE_TRUNCATE_INITIALIZE_HEADER_MASK    (0x7F<<0)
#define SQLITE_TRUNCATE_JOURNALMODE_WAL           (0x1<<0)
#define SQLITE_TRUNCATE_AUTOVACUUM_MASK           (0x3<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_OFF            (0x1<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_FULL           (0x2<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_INCREMENTAL    (0x3<<2)
#define SQLITE_TRUNCATE_PAGESIZE_MASK             (0x7<<4)
#define SQLITE_TRUNCATE_PAGESIZE_1024             (0x1<<4)
#define SQLITE_TRUNCATE_PAGESIZE_2048             (0x2<<4)
#define SQLITE_TRUNCATE_PAGESIZE_4096             (0x3<<4)
#define SQLITE_TRUNCATE_PAGESIZE_8192             (0x4<<4)
#define SQLITE_TRUNCATE_FORCE                     (0x1<<7)

/*
** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control()
** and a sqlite3 pointer to another open database file to safely copy the 
** contents of that database file into the receiving database.
*/
#define SQLITE_FCNTL_REPLACE_DATABASE       102
#define SQLITE_REPLACE_DATABASE             SQLITE_FCNTL_REPLACE_DATABASE

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif

Changes to src/sqliteInt.h.

327
328
329
330
331
332
333
















334
335
336
337
338
339
340
....
4879
4880
4881
4882
4883
4884
4885
























4886
4887
4888
4889
4890
4891
4892
#if defined(SQLITE_SYSTEM_MALLOC) \
  + defined(SQLITE_WIN32_MALLOC) \
  + defined(SQLITE_ZERO_MALLOC) \
  + defined(SQLITE_MEMDEBUG)==0
# define SQLITE_SYSTEM_MALLOC 1
#endif

















/*
** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the
** sizes of memory allocations below this value where possible.
*/
#if !defined(SQLITE_MALLOC_SOFT_LIMIT)
# define SQLITE_MALLOC_SOFT_LIMIT 1024
#endif
................................................................................
# define sqlite3MemdebugHasType(X,Y)  1
# define sqlite3MemdebugNoType(X,Y)   1
#endif
#define MEMTYPE_HEAP       0x01  /* General heap allocations */
#define MEMTYPE_LOOKASIDE  0x02  /* Heap that might have been lookaside */
#define MEMTYPE_PCACHE     0x04  /* Page cache allocations */

























/*
** Threading interface
*/
#if SQLITE_MAX_WORKER_THREADS>0
int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
int sqlite3ThreadJoin(SQLiteThread*, void**);
#endif







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







 







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







327
328
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
....
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
#if defined(SQLITE_SYSTEM_MALLOC) \
  + defined(SQLITE_WIN32_MALLOC) \
  + defined(SQLITE_ZERO_MALLOC) \
  + defined(SQLITE_MEMDEBUG)==0
# define SQLITE_SYSTEM_MALLOC 1
#endif

/*
** This is a magic string that appears at the beginning of every
** SQLite database in order to identify the file as a real database.
**
** You can change this value at compile-time by specifying a
** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
** header must be exactly 16 bytes including the zero-terminator so
** the string itself should be 15 characters long.  If you change
** the header, then your custom library will not be able to read 
** databases generated by the standard tools and the standard tools
** will not be able to read databases created by your custom library.
*/
#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
#  define SQLITE_FILE_HEADER "SQLite format 3"
#endif

/*
** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the
** sizes of memory allocations below this value where possible.
*/
#if !defined(SQLITE_MALLOC_SOFT_LIMIT)
# define SQLITE_MALLOC_SOFT_LIMIT 1024
#endif
................................................................................
# define sqlite3MemdebugHasType(X,Y)  1
# define sqlite3MemdebugNoType(X,Y)   1
#endif
#define MEMTYPE_HEAP       0x01  /* General heap allocations */
#define MEMTYPE_LOOKASIDE  0x02  /* Heap that might have been lookaside */
#define MEMTYPE_PCACHE     0x04  /* Page cache allocations */

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)

/*
** An instance of the following structure is used to hold the process ID
** and return-by-reference lockstate value.  The SQLITE_FCNTL_LOCKSTATE_PID
** requires the 4th argument to sqlite3_file_control to be a pointer to an
** instance of LockstatePID initialized with a LockstatePID.pid value equal
** to a process ID to be tested, or the special value SQLITE_LOCKSTATE_ANYPID
** The Lockstate.state value is always set to one of the following values
** when sqlite3_file_control returns:
** 
**   SQLITE_LOCKSTATE_OFF    no active sqlite file locks match the specified pid
**   SQLITE_LOCKSTATE_ON     active sqlite file locks match the specified pid
**   SQLITE_LOCKSTATE_NOTADB path points to a file that is not an sqlite db file
**   SQLITE_LOCKSTATE_ERROR  path was not vaild or was unreadable
*/
typedef struct LockstatePID LockstatePID;
struct LockstatePID {
  pid_t pid;                 /* Process ID to test */
  int state;                 /* The state of the lock (return value) */
};

#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */

/*
** Threading interface
*/
#if SQLITE_MAX_WORKER_THREADS>0
int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
int sqlite3ThreadJoin(SQLiteThread*, void**);
#endif

Changes to src/test1.c.

4074
4075
4076
4077
4078
4079
4080


















4081
4082
4083
4084
4085
4086
4087
....
5919
5920
5921
5922
5923
5924
5925


























































































5926
5927
5928
5929
5930
5931
5932
....
6063
6064
6065
6066
6067
6068
6069




















































































6070
6071
6072
6073
6074
6075
6076
....
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
....
7968
7969
7970
7971
7972
7973
7974

7975
7976
7977
7978
7979
7980
7981
....
8083
8084
8085
8086
8087
8088
8089




8090
8091
8092
8093
8094
8095
8096
....
8097
8098
8099
8100
8101
8102
8103


8104
8105
8106
8107
8108
8109
8110
    Tcl_WrongNumArgs(interp, 1, objv, "STMT");
    return TCL_ERROR;
  }
  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt)));
  return TCL_OK;
}



















/*
** Usage:   sqlite3_sleep MILLISECONDS
*/
static int SQLITE_TCLAPI test_sleep(
  void * clientData,
  Tcl_Interp *interp,
................................................................................
  }else{
    sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers);
    Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE);
    return TCL_OK;
  }
}



























































































/*
** tclcmd:   file_control_chunksize_test DB DBNAME SIZE
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/
................................................................................
      Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
      return TCL_ERROR;
    }
  }
#endif
  return TCL_OK;  
}





















































































#if SQLITE_OS_WIN
/*
** tclcmd:   file_control_win32_av_retry DB  NRETRY  DELAY
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_WIN32_AV_RETRY opcode.
................................................................................
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
  sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}

/*
** tclcmd:   file_control_powersafe_overwrite DB PSOW-FLAG
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode.
*/
static int SQLITE_TCLAPI file_control_powersafe_overwrite(
................................................................................
     { "sqlite3_bind_text",             test_bind_text     ,0 },
     { "sqlite3_bind_text16",           test_bind_text16   ,0 },
     { "sqlite3_bind_blob",             test_bind_blob     ,0 },
     { "sqlite3_bind_parameter_count",  test_bind_parameter_count, 0},
     { "sqlite3_bind_parameter_name",   test_bind_parameter_name,  0},
     { "sqlite3_bind_parameter_index",  test_bind_parameter_index, 0},
     { "sqlite3_clear_bindings",        test_clear_bindings, 0},

     { "sqlite3_sleep",                 test_sleep,          0},
     { "sqlite3_errcode",               test_errcode       ,0 },
     { "sqlite3_extended_errcode",      test_ex_errcode    ,0 },
     { "sqlite3_errmsg",                test_errmsg        ,0 },
     { "sqlite3_errmsg16",              test_errmsg16      ,0 },
     { "sqlite3_open",                  test_open          ,0 },
     { "sqlite3_open16",                test_open16        ,0 },
................................................................................
     { "vfs_unlink_test",            vfs_unlink_test,     0   },
     { "vfs_initfail_test",          vfs_initfail_test,   0   },
     { "vfs_unregister_all",         vfs_unregister_all,  0   },
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },




     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
     { "file_control_data_version",   file_control_data_version,    0   },
#if SQLITE_OS_WIN
     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
     { "file_control_win32_get_handle", file_control_win32_get_handle, 0  },
     { "file_control_win32_set_handle", file_control_win32_set_handle, 0  },
................................................................................
#endif
     { "file_control_persist_wal",    file_control_persist_wal,     0   },
     { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
     { "file_control_vfsname",        file_control_vfsname,         0   },
     { "file_control_tempfilename",   file_control_tempfilename,    0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },



     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },
     { "add_test_function",       test_function, 0           },
     { "add_test_utf16bin_collate",    test_utf16bin_collate, 0        },







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







 







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







 







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







 







<







 







>







 







>
>
>
>







 







>
>







4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
....
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
....
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
....
6389
6390
6391
6392
6393
6394
6395

6396
6397
6398
6399
6400
6401
6402
....
8159
8160
8161
8162
8163
8164
8165
8166
8167
8168
8169
8170
8171
8172
8173
....
8275
8276
8277
8278
8279
8280
8281
8282
8283
8284
8285
8286
8287
8288
8289
8290
8291
8292
....
8293
8294
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
8306
8307
8308
    Tcl_WrongNumArgs(interp, 1, objv, "STMT");
    return TCL_ERROR;
  }
  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt)));
  return TCL_OK;
}

/*
 ** Usage:   sqlite3_clear_bindings STMT
 **
 */
static int test_clear_bindings_null(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){  
  if( objc!=1 ){
    return TCL_ERROR;
  }
  /* test for handling NULL <rdar://problem/6646331> */
  Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(0)));
  return TCL_OK;
}

/*
** Usage:   sqlite3_sleep MILLISECONDS
*/
static int SQLITE_TCLAPI test_sleep(
  void * clientData,
  Tcl_Interp *interp,
................................................................................
  }else{
    sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers);
    Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE);
    return TCL_OK;
  }
}

#ifdef __APPLE__
/* From sqlite3_private.h */
# ifndef SQLITE_TRUNCATE_DATABASE
# define SQLITE_TRUNCATE_DATABASE      101
# define SQLITE_TRUNCATE_JOURNALMODE_WAL           (0x1<<0)
# define SQLITE_TRUNCATE_AUTOVACUUM_MASK           (0x3<<2)
# define SQLITE_TRUNCATE_AUTOVACUUM_OFF            (0x1<<2)
# define SQLITE_TRUNCATE_AUTOVACUUM_FULL           (0x2<<2)
# define SQLITE_TRUNCATE_AUTOVACUUM_INCREMENTAL    (0x3<<2)
# define SQLITE_TRUNCATE_PAGESIZE_MASK             (0x7<<4)
# define SQLITE_TRUNCATE_PAGESIZE_1024             (0x1<<4)
# define SQLITE_TRUNCATE_PAGESIZE_2048             (0x2<<4)
# define SQLITE_TRUNCATE_PAGESIZE_4096             (0x3<<4)
# define SQLITE_TRUNCATE_PAGESIZE_8192             (0x4<<4)
# endif
# ifndef SQLITE_REPLACE_DATABASE
# define SQLITE_REPLACE_DATABASE       102
# endif

/*
** tclcmd:   file_control_truncate_test DB
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_TRUNCATE_DATABASE verb.
*/
static int file_control_truncate_test(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  int flags;
  int rc;
  
  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " DB FLAGS", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &flags) ){
    return TCL_ERROR;
  }
  rc = sqlite3_file_control(db, NULL, SQLITE_TRUNCATE_DATABASE, &flags);
  if( rc ){ 
    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
    return TCL_ERROR; 
  }
  return TCL_OK;  
}

/*
** tclcmd:   file_control_replace_test DB
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_REPLACE_DATABASE verb.
*/
static int file_control_replace_test(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *src_db;
  sqlite3 *dst_db;
  int rc;
  
  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " DST_DB SRC_DB", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &dst_db) ){
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[2]), &src_db) ){
    return TCL_ERROR;
  }
  rc = sqlite3_file_control(dst_db, NULL, SQLITE_REPLACE_DATABASE, src_db);
  if( rc ){ 
    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
    return TCL_ERROR; 
  }
  return TCL_OK;  
}
#endif /* __APPLE__ */

/*
** tclcmd:   file_control_chunksize_test DB DBNAME SIZE
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/
................................................................................
      Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
      return TCL_ERROR;
    }
  }
#endif
  return TCL_OK;  
}

#ifdef __APPLE__
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/errno.h>
#endif

/*
 ** tclcmd:   path_is_local PWD
 */
static int path_is_local(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
#ifdef __APPLE__
  const char *zPath;
  int nPath;
  struct statfs fsInfo;
  
  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " PATH", 0);
    return TCL_ERROR;
  }
  zPath = Tcl_GetStringFromObj(objv[1], &nPath);
  if( statfs(zPath, &fsInfo) == -1 ){
    int err = errno;
    Tcl_AppendResult(interp, "Error calling statfs on path",
                     Tcl_NewIntObj(err), 0);
    return TCL_ERROR;
  }
  if( fsInfo.f_flags&MNT_LOCAL ){
    Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); 
  } else {
    Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); 
  }
#else
  Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); 
#endif
  
  return TCL_OK;  
}

/*
 ** tclcmd:   path_is_dos PWD
 */
static int path_is_dos(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
#ifdef __APPLE__
  const char *zPath;
  int nPath;
  struct statfs fsInfo;
  
  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " PATH", 0);
    return TCL_ERROR;
  }
  zPath = Tcl_GetStringFromObj(objv[1], &nPath);
  if( statfs(zPath, &fsInfo) == -1 ){
    int err = errno;
    Tcl_AppendResult(interp, "Error calling statfs on path",
                     Tcl_NewIntObj(err), 0);
    return TCL_ERROR;
  }
  if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
    Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); 
  } else if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
    Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); 
  } else {
    Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); 
  }
#else
  Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); 
#endif
  
  return TCL_OK;  
}

#if SQLITE_OS_WIN
/*
** tclcmd:   file_control_win32_av_retry DB  NRETRY  DELAY
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_WIN32_AV_RETRY opcode.
................................................................................
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
  sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}

/*
** tclcmd:   file_control_powersafe_overwrite DB PSOW-FLAG
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode.
*/
static int SQLITE_TCLAPI file_control_powersafe_overwrite(
................................................................................
     { "sqlite3_bind_text",             test_bind_text     ,0 },
     { "sqlite3_bind_text16",           test_bind_text16   ,0 },
     { "sqlite3_bind_blob",             test_bind_blob     ,0 },
     { "sqlite3_bind_parameter_count",  test_bind_parameter_count, 0},
     { "sqlite3_bind_parameter_name",   test_bind_parameter_name,  0},
     { "sqlite3_bind_parameter_index",  test_bind_parameter_index, 0},
     { "sqlite3_clear_bindings",        test_clear_bindings, 0},
     { "sqlite3_clear_bindings_null",   test_clear_bindings_null, 0},
     { "sqlite3_sleep",                 test_sleep,          0},
     { "sqlite3_errcode",               test_errcode       ,0 },
     { "sqlite3_extended_errcode",      test_ex_errcode    ,0 },
     { "sqlite3_errmsg",                test_errmsg        ,0 },
     { "sqlite3_errmsg16",              test_errmsg16      ,0 },
     { "sqlite3_open",                  test_open          ,0 },
     { "sqlite3_open16",                test_open16        ,0 },
................................................................................
     { "vfs_unlink_test",            vfs_unlink_test,     0   },
     { "vfs_initfail_test",          vfs_initfail_test,   0   },
     { "vfs_unregister_all",         vfs_unregister_all,  0   },
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
#ifdef __APPLE__
     { "file_control_truncate_test", file_control_truncate_test,  0   },
     { "file_control_replace_test", file_control_replace_test,  0   },
#endif 
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
     { "file_control_data_version",   file_control_data_version,    0   },
#if SQLITE_OS_WIN
     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
     { "file_control_win32_get_handle", file_control_win32_get_handle, 0  },
     { "file_control_win32_set_handle", file_control_win32_set_handle, 0  },
................................................................................
#endif
     { "file_control_persist_wal",    file_control_persist_wal,     0   },
     { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
     { "file_control_vfsname",        file_control_vfsname,         0   },
     { "file_control_tempfilename",   file_control_tempfilename,    0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },
     { "path_is_local",              path_is_local,  0   },
     { "path_is_dos",                path_is_dos,  0   },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },
     { "add_test_function",       test_function, 0           },
     { "add_test_utf16bin_collate",    test_utf16bin_collate, 0        },

Changes to src/test_config.c.

610
611
612
613
614
615
616
617















618
619
620
621
622
623
624
...
745
746
747
748
749
750
751
















752
753
754
755
756
757
758
  Tcl_SetVar2(interp,"sqlite_options","lock_proxy_pragmas","0",TCL_GLOBAL_ONLY);
#endif
#if defined(SQLITE_PREFER_PROXY_LOCKING) && defined(__APPLE__)
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","0",TCL_GLOBAL_ONLY);
#endif
    















    
#ifdef SQLITE_OMIT_SHARED_CACHE
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "1", TCL_GLOBAL_ONLY);
#endif

................................................................................
#endif

#ifdef SQLITE_ENABLE_SQLLOG
  Tcl_SetVar2(interp, "sqlite_options", "sqllog", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "sqllog", "0", TCL_GLOBAL_ONLY);
#endif

















#ifdef SQLITE_ENABLE_URI_00_ERROR
  Tcl_SetVar2(interp, "sqlite_options", "uri_00_error", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "uri_00_error", "0", TCL_GLOBAL_ONLY);
#endif








<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







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







610
611
612
613
614
615
616

617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
...
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
  Tcl_SetVar2(interp,"sqlite_options","lock_proxy_pragmas","0",TCL_GLOBAL_ONLY);
#endif
#if defined(SQLITE_PREFER_PROXY_LOCKING) && defined(__APPLE__)
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","0",TCL_GLOBAL_ONLY);
#endif

#if defined(SQLITE_ENABLE_PURGEABLE_PCACHE) && defined(__APPLE__)
  Tcl_SetVar2(interp,"sqlite_options","enable_purgeable_pcache","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","enable_purgeable_pcache","0",TCL_GLOBAL_ONLY);
#endif
#if SQLITE_DEFAULT_CKPTFULLFSYNC
  Tcl_SetVar2(interp,"sqlite_options","default_ckptfullfsync","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","default_ckptfullfsync","0",TCL_GLOBAL_ONLY);
#endif
#if SQLITE_ENABLE_PERSIST_WAL
  Tcl_SetVar2(interp,"sqlite_options","enable_persist_wal","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","enable_persist_wal","0",TCL_GLOBAL_ONLY);
#endif
    
#ifdef SQLITE_OMIT_SHARED_CACHE
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "1", TCL_GLOBAL_ONLY);
#endif

................................................................................
#endif

#ifdef SQLITE_ENABLE_SQLLOG
  Tcl_SetVar2(interp, "sqlite_options", "sqllog", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "sqllog", "0", TCL_GLOBAL_ONLY);
#endif

#ifdef __APPLE__
# if  defined(__ppc__)
  Tcl_SetVar2(interp, "os_options", "arch", "ppc", TCL_GLOBAL_ONLY);
# elif defined(__i386__)
  Tcl_SetVar2(interp, "os_options", "arch", "i386", TCL_GLOBAL_ONLY);
# elif defined(__x86_64__)
  Tcl_SetVar2(interp, "os_options", "arch", "x86_64", TCL_GLOBAL_ONLY);
# elif defined(__arm__)
  Tcl_SetVar2(interp, "os_options", "arch", "arm", TCL_GLOBAL_ONLY);
# else
#  error Unrecognized architecture for exec_options
# endif
#else
  Tcl_SetVar2(interp, "os_options", "arch", "unknown", TCL_GLOBAL_ONLY);
#endif

#ifdef SQLITE_ENABLE_URI_00_ERROR
  Tcl_SetVar2(interp, "sqlite_options", "uri_00_error", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "uri_00_error", "0", TCL_GLOBAL_ONLY);
#endif

Changes to src/test_superlock.c.

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
...
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
...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
}

/*
** Release a superlock held on a database file. The argument passed to 
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
    if( rc==SQLITE_OK ){
................................................................................
**
** If a required lock cannot be obtained immediately and the xBusy parameter
** to this function is not NULL, then xBusy is invoked in the same way
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */

  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;
................................................................................

  pLock = sqlite3_malloc(sizeof(Superlock));
  if( !pLock ) return SQLITE_NOMEM;
  memset(pLock, 0, sizeof(Superlock));

  /* Open a database handle on the file to superlock. */
  rc = sqlite3_open_v2(
      zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs
  );

  /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
  ** a WAL database, this is all we need to do.  
  **
  ** A wrapper function is used to invoke the busy-handler instead of
  ** registering the busy-handler function supplied by the user directly
................................................................................
  }
  if( objc>4 ){
    busy.interp = interp;
    busy.pScript = objv[4];
    xBusy = superlock_busy;
  }

  rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock);
  assert( rc==SQLITE_OK || pLock==0 );
  assert( rc!=SQLITE_OK || pLock!=0 );

  if( rc!=SQLITE_OK ){
    extern const char *sqlite3ErrStr(int);
    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);







|







 







|


>







 







|







 







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
...
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
...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
}

/*
** Release a superlock held on a database file. The argument passed to 
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
static void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
    if( rc==SQLITE_OK ){
................................................................................
**
** If a required lock cannot be obtained immediately and the xBusy parameter
** to this function is not NULL, then xBusy is invoked in the same way
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
static int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */
  int flags,                      /* Additional flags to pass to sqlite3_open_v2 */
  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;
................................................................................

  pLock = sqlite3_malloc(sizeof(Superlock));
  if( !pLock ) return SQLITE_NOMEM;
  memset(pLock, 0, sizeof(Superlock));

  /* Open a database handle on the file to superlock. */
  rc = sqlite3_open_v2(
    zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|flags, zVfs
  );

  /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
  ** a WAL database, this is all we need to do.  
  **
  ** A wrapper function is used to invoke the busy-handler instead of
  ** registering the busy-handler function supplied by the user directly
................................................................................
  }
  if( objc>4 ){
    busy.interp = interp;
    busy.pScript = objv[4];
    xBusy = superlock_busy;
  }

  rc = sqlite3demo_superlock(zPath, zVfs, 0, xBusy, &busy, &pLock);
  assert( rc==SQLITE_OK || pLock==0 );
  assert( rc!=SQLITE_OK || pLock!=0 );

  if( rc!=SQLITE_OK ){
    extern const char *sqlite3ErrStr(int);
    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);

Changes to src/vdbe.c.

697
698
699
700
701
702
703
704

705
706
707
708
709
710
711
  }
#endif
  if( p->rc==SQLITE_NOMEM ){
    /* This happens if a malloc() inside a call to sqlite3_column_text() or
    ** sqlite3_column_text16() failed.  */
    goto no_mem;
  }
  assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );

  assert( p->bIsReader || p->readOnly!=0 );
  p->iCurrentTime = 0;
  assert( p->explain==0 );
  p->pResultSet = 0;
  db->busyHandler.nBusy = 0;
  if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
  sqlite3VdbeIOTraceSql(p);







|
>







697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  }
#endif
  if( p->rc==SQLITE_NOMEM ){
    /* This happens if a malloc() inside a call to sqlite3_column_text() or
    ** sqlite3_column_text16() failed.  */
    goto no_mem;
  }
  assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY
            || (p->rc&0xFF)==SQLITE_LOCKED );
  assert( p->bIsReader || p->readOnly!=0 );
  p->iCurrentTime = 0;
  assert( p->explain==0 );
  p->pResultSet = 0;
  db->busyHandler.nBusy = 0;
  if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
  sqlite3VdbeIOTraceSql(p);

Changes to src/vdbeapi.c.

11
12
13
14
15
16
17



18
19
20
21
22
23
24
...
100
101
102
103
104
105
106



107
108
109
110
111
112
113
...
126
127
128
129
130
131
132



133
134
135
136
137
138
139
...
145
146
147
148
149
150
151







152
153
154
155
156
157
158
159
....
1410
1411
1412
1413
1414
1415
1416



1417
1418
1419
1420
1421
1422
1423
....
1432
1433
1434
1435
1436
1437
1438



1439
1440
1441
1442
1443
1444
1445
1446



1447
1448
1449
1450
1451



1452
1453
1454
1455
1456
1457
1458
1459
1460
1461



1462
1463
1464
1465
1466
1467
1468
....
1486
1487
1488
1489
1490
1491
1492



1493
1494
1495
1496
1497
1498
1499
....
1512
1513
1514
1515
1516
1517
1518



1519
1520
1521
1522
1523
1524
1525
....
1535
1536
1537
1538
1539
1540
1541



1542
1543
1544
1545
1546
1547
1548
....
1549
1550
1551
1552
1553
1554
1555



1556
1557
1558
1559
1560
1561
1562
*************************************************************************
**
** This file contains code use to implement APIs that are part of the
** VDBE.
*/
#include "sqliteInt.h"
#include "vdbeInt.h"




#ifndef SQLITE_OMIT_DEPRECATED
/*
** Return TRUE (non-zero) of the statement supplied as an argument needs
** to be recompiled.  A statement needs to be recompiled whenever the
** execution environment changes in a way that would alter the program
** that sqlite3_prepare() generates.  For example, if new functions or
................................................................................
  int rc;
  if( pStmt==0 ){
    /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
    ** pointer is a harmless no-op. */
    rc = SQLITE_OK;
  }else{
    Vdbe *v = (Vdbe*)pStmt;



    sqlite3 *db = v->db;
    if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
    sqlite3_mutex_enter(db->mutex);
    checkProfileCallback(db, v);
    rc = sqlite3VdbeFinalize(v);
    rc = sqlite3ApiExit(db, rc);
    sqlite3LeaveMutexAndCloseZombie(db);
................................................................................
int sqlite3_reset(sqlite3_stmt *pStmt){
  int rc;
  if( pStmt==0 ){
    rc = SQLITE_OK;
  }else{
    Vdbe *v = (Vdbe*)pStmt;
    sqlite3 *db = v->db;



    sqlite3_mutex_enter(db->mutex);
    checkProfileCallback(db, v);
    rc = sqlite3VdbeReset(v);
    sqlite3VdbeRewind(v);
    assert( (rc & (db->errMask))==rc );
    rc = sqlite3ApiExit(db, rc);
    sqlite3_mutex_leave(db->mutex);
................................................................................
** Set all the parameters in the compiled SQL statement to NULL.
*/
int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
  int i;
  int rc = SQLITE_OK;
  Vdbe *p = (Vdbe*)pStmt;
#if SQLITE_THREADSAFE







  sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
#endif
  sqlite3_mutex_enter(mutex);
  for(i=0; i<p->nVar; i++){
    sqlite3VdbeMemRelease(&p->aVar[i]);
    p->aVar[i].flags = MEM_Null;
  }
  assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
................................................................................
int sqlite3_bind_blob(
  sqlite3_stmt *pStmt, 
  int i, 
  const void *zData, 
  int nData, 
  void (*xDel)(void*)
){



#ifdef SQLITE_ENABLE_API_ARMOR
  if( nData<0 ) return SQLITE_MISUSE_BKPT;
#endif
  return bindText(pStmt, i, zData, nData, xDel, 0);
}
int sqlite3_bind_blob64(
  sqlite3_stmt *pStmt, 
................................................................................
  }else{
    return bindText(pStmt, i, zData, (int)nData, xDel, 0);
  }
}
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;



  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}
int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){



  return sqlite3_bind_int64(p, i, (i64)iValue);
}
int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;



  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}
int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
  int rc;
  Vdbe *p = (Vdbe*)pStmt;



  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}
int sqlite3_bind_pointer(
................................................................................
int sqlite3_bind_text( 
  sqlite3_stmt *pStmt, 
  int i, 
  const char *zData, 
  int nData, 
  void (*xDel)(void*)
){



  return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
int sqlite3_bind_text64( 
  sqlite3_stmt *pStmt, 
  int i, 
  const char *zData, 
  sqlite3_uint64 nData, 
................................................................................
int sqlite3_bind_text16(
  sqlite3_stmt *pStmt, 
  int i, 
  const void *zData, 
  int nData, 
  void (*xDel)(void*)
){



  return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
  int rc;
  switch( sqlite3_value_type((sqlite3_value*)pValue) ){
    case SQLITE_INTEGER: {
................................................................................
        rc = sqlite3_bind_zeroblob(pStmt, i, pValue->u.nZero);
      }else{
        rc = sqlite3_bind_blob(pStmt, i, pValue->z, pValue->n,SQLITE_TRANSIENT);
      }
      break;
    }
    case SQLITE_TEXT: {



      rc = bindText(pStmt,i,  pValue->z, pValue->n, SQLITE_TRANSIENT,
                              pValue->enc);
      break;
    }
    default: {
      rc = sqlite3_bind_null(pStmt, i);
      break;
................................................................................
    }
  }
  return rc;
}
int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;



  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>
>
>
>
>
|







 







>
>
>







 







>
>
>








>
>
>





>
>
>










>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
....
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
....
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
....
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
....
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
....
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
....
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
*************************************************************************
**
** This file contains code use to implement APIs that are part of the
** VDBE.
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
#ifdef SQLITE_ENABLE_SQLRR
# include "sqlrr.h"
#endif 

#ifndef SQLITE_OMIT_DEPRECATED
/*
** Return TRUE (non-zero) of the statement supplied as an argument needs
** to be recompiled.  A statement needs to be recompiled whenever the
** execution environment changes in a way that would alter the program
** that sqlite3_prepare() generates.  For example, if new functions or
................................................................................
  int rc;
  if( pStmt==0 ){
    /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
    ** pointer is a harmless no-op. */
    rc = SQLITE_OK;
  }else{
    Vdbe *v = (Vdbe*)pStmt;
#ifdef SQLITE_ENABLE_SQLRR
    SRRecFinalize(pStmt);
#endif
    sqlite3 *db = v->db;
    if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
    sqlite3_mutex_enter(db->mutex);
    checkProfileCallback(db, v);
    rc = sqlite3VdbeFinalize(v);
    rc = sqlite3ApiExit(db, rc);
    sqlite3LeaveMutexAndCloseZombie(db);
................................................................................
int sqlite3_reset(sqlite3_stmt *pStmt){
  int rc;
  if( pStmt==0 ){
    rc = SQLITE_OK;
  }else{
    Vdbe *v = (Vdbe*)pStmt;
    sqlite3 *db = v->db;
#ifdef SQLITE_ENABLE_SQLRR
    SRRecReset(pStmt);
#endif
    sqlite3_mutex_enter(db->mutex);
    checkProfileCallback(db, v);
    rc = sqlite3VdbeReset(v);
    sqlite3VdbeRewind(v);
    assert( (rc & (db->errMask))==rc );
    rc = sqlite3ApiExit(db, rc);
    sqlite3_mutex_leave(db->mutex);
................................................................................
** Set all the parameters in the compiled SQL statement to NULL.
*/
int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
  int i;
  int rc = SQLITE_OK;
  Vdbe *p = (Vdbe*)pStmt;
#if SQLITE_THREADSAFE
  sqlite3_mutex *mutex=NULL;
#endif
  if( NULL==pStmt ){ return SQLITE_OK; } /* <rdar://problem/6646331> */
#ifdef SQLITE_ENABLE_SQLRR
  SRRecClearBindings(pStmt);  
#endif
#if SQLITE_THREADSAFE
  mutex = ((Vdbe*)pStmt)->db->mutex;
#endif
  sqlite3_mutex_enter(mutex);
  for(i=0; i<p->nVar; i++){
    sqlite3VdbeMemRelease(&p->aVar[i]);
    p->aVar[i].flags = MEM_Null;
  }
  assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
................................................................................
int sqlite3_bind_blob(
  sqlite3_stmt *pStmt, 
  int i, 
  const void *zData, 
  int nData, 
  void (*xDel)(void*)
){
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindBlob(pStmt, i, zData, nData);
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
  if( nData<0 ) return SQLITE_MISUSE_BKPT;
#endif
  return bindText(pStmt, i, zData, nData, xDel, 0);
}
int sqlite3_bind_blob64(
  sqlite3_stmt *pStmt, 
................................................................................
  }else{
    return bindText(pStmt, i, zData, (int)nData, xDel, 0);
  }
}
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindDouble(pStmt, i, rValue);
#endif
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}
int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindInt64(p, i, (i64)iValue);
#endif
  return sqlite3_bind_int64(p, i, (i64)iValue);
}
int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindInt64(pStmt, i, iValue);
#endif
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}
int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
  int rc;
  Vdbe *p = (Vdbe*)pStmt;
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindNull(pStmt, i);
#endif
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}
int sqlite3_bind_pointer(
................................................................................
int sqlite3_bind_text( 
  sqlite3_stmt *pStmt, 
  int i, 
  const char *zData, 
  int nData, 
  void (*xDel)(void*)
){
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindText(pStmt, i, zData, nData);
#endif
  return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
int sqlite3_bind_text64( 
  sqlite3_stmt *pStmt, 
  int i, 
  const char *zData, 
  sqlite3_uint64 nData, 
................................................................................
int sqlite3_bind_text16(
  sqlite3_stmt *pStmt, 
  int i, 
  const void *zData, 
  int nData, 
  void (*xDel)(void*)
){
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindText(pStmt, i, zData, nData);
#endif
  return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
  int rc;
  switch( sqlite3_value_type((sqlite3_value*)pValue) ){
    case SQLITE_INTEGER: {
................................................................................
        rc = sqlite3_bind_zeroblob(pStmt, i, pValue->u.nZero);
      }else{
        rc = sqlite3_bind_blob(pStmt, i, pValue->z, pValue->n,SQLITE_TRANSIENT);
      }
      break;
    }
    case SQLITE_TEXT: {
#ifdef SQLITE_ENABLE_SQLRR
      SRRecBindText(pStmt, i, pValue->z, pValue->n);
#endif
      rc = bindText(pStmt,i,  pValue->z, pValue->n, SQLITE_TRANSIENT,
                              pValue->enc);
      break;
    }
    default: {
      rc = sqlite3_bind_null(pStmt, i);
      break;
................................................................................
    }
  }
  return rc;
}
int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;
#ifdef SQLITE_ENABLE_SQLRR
  SRRecBindBlob(pStmt, i, NULL, n);
#endif
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
    sqlite3_mutex_leave(p->db->mutex);
  }
  return rc;
}

Changes to src/wal.c.

1337
1338
1339
1340
1341
1342
1343

1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
....
1380
1381
1382
1383
1384
1385
1386



1387

1388
1389
1390
1391
1392
1393
1394
1395
1396
....
2092
2093
2094
2095
2096
2097
2098



2099
2100
2101
2102
2103
2104
2105
....
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
....
3205
3206
3207
3208
3209
3210
3211




3212
3213
3214
3215
3216
3217
3218
....
3248
3249
3250
3251
3252
3253
3254



3255


3256
3257
3258
3259
3260

3261





3262
3263
3264
3265

3266
3267
3268
3269
3270
3271
3272
....
3417
3418
3419
3420
3421
3422
3423







3424
3425
3426
3427
3428
3429
3430
....
3452
3453
3454
3455
3456
3457
3458




3459

3460
3461
3462
3463
3464
3465
3466
....
3487
3488
3489
3490
3491
3492
3493




3494

3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505



3506
3507
3508
3509
3510
3511
3512
*/
int sqlite3WalOpen(
  sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
  sqlite3_file *pDbFd,            /* The open database file */
  const char *zWalName,           /* Name of the WAL file */
  int bNoShm,                     /* True to run in heap-memory mode */
  i64 mxWalSize,                  /* Truncate WAL to this size on reset */

  Wal **ppWal                     /* OUT: Allocated Wal handle */
){
  int rc;                         /* Return Code */
  Wal *pRet;                      /* Object to allocate and return */
  int flags;                      /* Flags passed to OsOpen() */

  assert( zWalName && zWalName[0] );
  assert( pDbFd );

  /* In the amalgamation, the os_unix.c and os_win.c source files come before
  ** this source file.  Verify that the #defines of the locking byte offsets
  ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
................................................................................
  pRet->mxWalSize = mxWalSize;
  pRet->zWalName = zWalName;
  pRet->syncHeader = 1;
  pRet->padToSectorBoundary = 1;
  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);

  /* Open file handle on the write-ahead log file. */



  flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);

  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
  if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
    pRet->readOnly = WAL_RDONLY;
  }

  if( rc!=SQLITE_OK ){
    walIndexClose(pRet, 0);
    sqlite3OsClose(pRet->pWalFd);
    sqlite3_free(pRet);
................................................................................
  **
  ** There are two copies of the header at the beginning of the wal-index.
  ** When reading, read [0] first then [1].  Writes are in the reverse order.
  ** Memory barriers are used to prevent the compiler or the hardware from
  ** reordering the reads and writes.
  */
  aHdr = walIndexHdr(pWal);



  memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
  walShmBarrier(pWal);
  memcpy(&h2, (void *)&aHdr[1], sizeof(h2));

  if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
    return 1;   /* Dirty read */
  }  
................................................................................
Pgno sqlite3WalDbsize(Wal *pWal){
  if( pWal && ALWAYS(pWal->readLock>=0) ){
    return pWal->hdr.nPage;
  }
  return 0;
}


/* 
** This function starts a write transaction on the WAL.
**
** A read transaction must have already been started by a prior call
** to sqlite3WalBeginReadTransaction().
**
** If another thread or process has written into the database since
................................................................................
*/
typedef struct WalWriter {
  Wal *pWal;                   /* The complete WAL information */
  sqlite3_file *pFd;           /* The WAL file to which we write */
  sqlite3_int64 iSyncPoint;    /* Fsync at this offset */
  int syncFlags;               /* Flags for the fsync */
  int szPage;                  /* Size of one page */




} WalWriter;

/*
** Write iAmt bytes of content into the WAL file beginning at iOffset.
** Do a sync when crossing the p->iSyncPoint boundary.
**
** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
................................................................................
  WalWriter *p,               /* Where to write the frame */
  PgHdr *pPage,               /* The page of the frame to be written */
  int nTruncate,              /* The commit flag.  Usually 0.  >0 for commit */
  sqlite3_int64 iOffset       /* Byte offset at which to write */
){
  int rc;                         /* Result code from subfunctions */
  void *pData;                    /* Data actually written */



  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */


#if defined(SQLITE_HAS_CODEC)
  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
#else
  pData = pPage->pData;
#endif

  walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);





  rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
  if( rc ) return rc;
  /* Write the page data */
  rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));

  return rc;
}

/*
** This function is called as part of committing a transaction within which
** one or more frames have been overwritten. It updates the checksums for
** all frames written to the wal file by the current transaction starting
................................................................................
  w.pWal = pWal;
  w.pFd = pWal->pWalFd;
  w.iSyncPoint = 0;
  w.syncFlags = sync_flags;
  w.szPage = szPage;
  iOffset = walFrameOffset(iFrame+1, szPage);
  szFrame = szPage + WAL_FRAME_HDRSIZE;








  /* Write all frames into the log file exactly once */
  for(p=pList; p; p=p->pDirty){
    int nDbSize;   /* 0 normally.  Positive == commit flag */

    /* Check if this page has already been written into the wal file by
    ** the current transaction. If so, overwrite the existing frame and
................................................................................
      }
    }

    iFrame++;
    assert( iOffset==walFrameOffset(iFrame, szPage) );
    nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
    rc = walWriteOneFrame(&w, p, nDbSize, iOffset);




    if( rc ) return rc;

    pLast = p;
    iOffset += szFrame;
    p->flags |= PGHDR_WAL_APPEND;
  }

  /* Recalculate checksums within the wal file if required. */
  if( isCommit && pWal->iReCksum ){
................................................................................
    if( pWal->padToSectorBoundary ){
      int sectorSize = sqlite3SectorSize(pWal->pWalFd);
      w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
      bSync = (w.iSyncPoint==iOffset);
      testcase( bSync );
      while( iOffset<w.iSyncPoint ){
        rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);




        if( rc ) return rc;

        iOffset += szFrame;
        nExtra++;
        assert( pLast!=0 );
      }
    }
    if( bSync ){
      assert( rc==SQLITE_OK );
      rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags));
    }
  }




  /* If this frame set completes the first transaction in the WAL and
  ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
  ** journal size limit, if possible.
  */
  if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
    i64 sz = pWal->mxWalSize;
    if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){







>




|







 







>
>
>
|
>
|
|







 







>
>
>







 







<







 







>
>
>
>







 







>
>
>

>
>





>

>
>
>
>
>




>







 







>
>
>
>
>
>
>







 







>
>
>
>
|
>







 







>
>
>
>
|
>











>
>
>







1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
....
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
....
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
....
2995
2996
2997
2998
2999
3000
3001

3002
3003
3004
3005
3006
3007
3008
....
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
....
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
....
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
....
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
....
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
*/
int sqlite3WalOpen(
  sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
  sqlite3_file *pDbFd,            /* The open database file */
  const char *zWalName,           /* Name of the WAL file */
  int bNoShm,                     /* True to run in heap-memory mode */
  i64 mxWalSize,                  /* Truncate WAL to this size on reset */
  int flags,                      /* VFS file protection flags */
  Wal **ppWal                     /* OUT: Allocated Wal handle */
){
  int rc;                         /* Return Code */
  Wal *pRet;                      /* Object to allocate and return */
  int vfsFlags;                   /* Flags passed to OsOpen() */

  assert( zWalName && zWalName[0] );
  assert( pDbFd );

  /* In the amalgamation, the os_unix.c and os_win.c source files come before
  ** this source file.  Verify that the #defines of the locking byte offsets
  ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
................................................................................
  pRet->mxWalSize = mxWalSize;
  pRet->zWalName = zWalName;
  pRet->syncHeader = 1;
  pRet->padToSectorBoundary = 1;
  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);

  /* Open file handle on the write-ahead log file. */
  if( flags&SQLITE_OPEN_READONLY ){
    vfsFlags = flags | SQLITE_OPEN_WAL;
  } else {
    vfsFlags = flags | (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
  }
  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, vfsFlags, &vfsFlags);
  if( rc==SQLITE_OK && vfsFlags&SQLITE_OPEN_READONLY ){
    pRet->readOnly = WAL_RDONLY;
  }

  if( rc!=SQLITE_OK ){
    walIndexClose(pRet, 0);
    sqlite3OsClose(pRet->pWalFd);
    sqlite3_free(pRet);
................................................................................
  **
  ** There are two copies of the header at the beginning of the wal-index.
  ** When reading, read [0] first then [1].  Writes are in the reverse order.
  ** Memory barriers are used to prevent the compiler or the hardware from
  ** reordering the reads and writes.
  */
  aHdr = walIndexHdr(pWal);
  if( aHdr==NULL ){
    return 1; /* Shouldn't be getting NULL from walIndexHdr, but we are */
  }
  memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
  walShmBarrier(pWal);
  memcpy(&h2, (void *)&aHdr[1], sizeof(h2));

  if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
    return 1;   /* Dirty read */
  }  
................................................................................
Pgno sqlite3WalDbsize(Wal *pWal){
  if( pWal && ALWAYS(pWal->readLock>=0) ){
    return pWal->hdr.nPage;
  }
  return 0;
}


/* 
** This function starts a write transaction on the WAL.
**
** A read transaction must have already been started by a prior call
** to sqlite3WalBeginReadTransaction().
**
** If another thread or process has written into the database since
................................................................................
*/
typedef struct WalWriter {
  Wal *pWal;                   /* The complete WAL information */
  sqlite3_file *pFd;           /* The WAL file to which we write */
  sqlite3_int64 iSyncPoint;    /* Fsync at this offset */
  int syncFlags;               /* Flags for the fsync */
  int szPage;                  /* Size of one page */
#if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED)
  void *aFrameBuf;             /* Frame buffer */
  size_t szFrameBuf;           /* Size of frame buffer */
#endif
} WalWriter;

/*
** Write iAmt bytes of content into the WAL file beginning at iOffset.
** Do a sync when crossing the p->iSyncPoint boundary.
**
** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
................................................................................
  WalWriter *p,               /* Where to write the frame */
  PgHdr *pPage,               /* The page of the frame to be written */
  int nTruncate,              /* The commit flag.  Usually 0.  >0 for commit */
  sqlite3_int64 iOffset       /* Byte offset at which to write */
){
  int rc;                         /* Result code from subfunctions */
  void *pData;                    /* Data actually written */
#if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED)
  u8 *aFrame = p->aFrameBuf;
#else
  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */
#endif
  
#if defined(SQLITE_HAS_CODEC)
  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
#else
  pData = pPage->pData;
#endif

  walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
  
#if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED)
  memcpy(&aFrame[WAL_FRAME_HDRSIZE], pData, p->szPage);
  rc = walWriteToLog(p, aFrame, (p->szPage + WAL_FRAME_HDRSIZE), iOffset);
#else
  rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
  if( rc ) return rc;
  /* Write the page data */
  rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
#endif
  return rc;
}

/*
** This function is called as part of committing a transaction within which
** one or more frames have been overwritten. It updates the checksums for
** all frames written to the wal file by the current transaction starting
................................................................................
  w.pWal = pWal;
  w.pFd = pWal->pWalFd;
  w.iSyncPoint = 0;
  w.syncFlags = sync_flags;
  w.szPage = szPage;
  iOffset = walFrameOffset(iFrame+1, szPage);
  szFrame = szPage + WAL_FRAME_HDRSIZE;
#if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED)
  w.aFrameBuf = (void *)malloc(szFrame);
  if( NULL==w.aFrameBuf ){
    return SQLITE_NOMEM;
  }
#endif


  /* Write all frames into the log file exactly once */
  for(p=pList; p; p=p->pDirty){
    int nDbSize;   /* 0 normally.  Positive == commit flag */

    /* Check if this page has already been written into the wal file by
    ** the current transaction. If so, overwrite the existing frame and
................................................................................
      }
    }

    iFrame++;
    assert( iOffset==walFrameOffset(iFrame, szPage) );
    nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
    rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
    if( rc ) {
#if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED)
      free(w.aFrameBuf);
#endif
      return rc;
    }
    pLast = p;
    iOffset += szFrame;
    p->flags |= PGHDR_WAL_APPEND;
  }

  /* Recalculate checksums within the wal file if required. */
  if( isCommit && pWal->iReCksum ){
................................................................................
    if( pWal->padToSectorBoundary ){
      int sectorSize = sqlite3SectorSize(pWal->pWalFd);
      w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
      bSync = (w.iSyncPoint==iOffset);
      testcase( bSync );
      while( iOffset<w.iSyncPoint ){
        rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
        if( rc ) {
#if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED)
          free(w.aFrameBuf);
#endif
          return rc;
        }
        iOffset += szFrame;
        nExtra++;
        assert( pLast!=0 );
      }
    }
    if( bSync ){
      assert( rc==SQLITE_OK );
      rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags));
    }
  }

#if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED)
  free(w.aFrameBuf);
#endif
  /* If this frame set completes the first transaction in the WAL and
  ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
  ** journal size limit, if possible.
  */
  if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
    i64 sz = pWal->mxWalSize;
    if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){

Changes to src/wal.h.

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
..
74
75
76
77
78
79
80



81
82
83
84
85
86
87

/* Connection to a write-ahead log (WAL) file. 
** There is one object of this type for each pager. 
*/
typedef struct Wal Wal;

/* Open and close a connection to a write-ahead log. */
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);

/* Set the limiting size of a WAL file. */
void sqlite3WalLimit(Wal*, i64);

/* Used by readers to open (lock) and close (unlock) a snapshot.  A 
** snapshot is like a read-transaction.  It is the state of the database
................................................................................
/* Read a page from the write-ahead log, if it is present. */
int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
int sqlite3WalReadFrame(Wal *, u32, int, u8 *);

/* If the WAL is not empty, return the size of the database. */
Pgno sqlite3WalDbsize(Wal *pWal);




/* Obtain or release the WRITER lock. */
int sqlite3WalBeginWriteTransaction(Wal *pWal);
int sqlite3WalEndWriteTransaction(Wal *pWal);

/* Undo any frames written (but not committed) to the log */
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);








|







 







>
>
>







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

/* Connection to a write-ahead log (WAL) file. 
** There is one object of this type for each pager. 
*/
typedef struct Wal Wal;

/* Open and close a connection to a write-ahead log. */
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, int, Wal**);
int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);

/* Set the limiting size of a WAL file. */
void sqlite3WalLimit(Wal*, i64);

/* Used by readers to open (lock) and close (unlock) a snapshot.  A 
** snapshot is like a read-transaction.  It is the state of the database
................................................................................
/* Read a page from the write-ahead log, if it is present. */
int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
int sqlite3WalReadFrame(Wal *, u32, int, u8 *);

/* If the WAL is not empty, return the size of the database. */
Pgno sqlite3WalDbsize(Wal *pWal);

/* If a WAL journal file has been created, return it */
sqlite3_file *sqlite3WalFile(Wal *pWal);
  
/* Obtain or release the WRITER lock. */
int sqlite3WalBeginWriteTransaction(Wal *pWal);
int sqlite3WalEndWriteTransaction(Wal *pWal);

/* Undo any frames written (but not committed) to the log */
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);

Changes to test/8_3_names.test.

142
143
144
145
146
147
148


149
150
151
152
153
154
155
##########################################################################
# WAL mode.
#
ifcapable !wal {
  finish_test
  return
}


db close
forcedelete test.db
do_test 8_3_names-5.0 {
  sqlite3 db file:./test.db?8_3_names=1
  load_static_extension db wholenumber
  db eval {
    PRAGMA journal_mode=WAL;







>
>







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
##########################################################################
# WAL mode.
#
ifcapable !wal {
  finish_test
  return
}
if ![wal_is_ok] { finish_test; return }

db close
forcedelete test.db
do_test 8_3_names-5.0 {
  sqlite3 db file:./test.db?8_3_names=1
  load_static_extension db wholenumber
  db eval {
    PRAGMA journal_mode=WAL;

Changes to test/altertab.test.

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
...
566
567
568
569
570
571
572




573
574
575
576
577
578
579
    INSERT INTO y1_segments VALUES(1, X'1234567890');
  } {1 {table y1_segments may not be modified}}

  do_catchsql_test 16.20 {
    DROP TABLE y1_segments;
  } {1 {table y1_segments may not be dropped}}

  do_catchsql_test 16.20 {
    ALTER TABLE y1_segments RENAME TO abc;
  } {1 {table y1_segments may not be altered}}
  sqlite3_db_config db DEFENSIVE 0
  do_catchsql_test 16.22 {
    ALTER TABLE y1_segments RENAME TO abc;
  } {0 {}}
  sqlite3_db_config db DEFENSIVE 1
................................................................................
  } {1 {object name reserved for internal use: y1_segments}}
  sqlite3_db_config db DEFENSIVE 0
  do_catchsql_test 16.25 {
    ALTER TABLE abc RENAME TO y1_segments;
  } {0 {}}
  sqlite3_db_config db DEFENSIVE 1





  do_execsql_test 16.30 {
    ALTER TABLE y1 RENAME TO z1;
  }

  do_execsql_test 16.40 {
    SELECT * FROM z1_segments;
  }







|







 







>
>
>
>







546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
    INSERT INTO y1_segments VALUES(1, X'1234567890');
  } {1 {table y1_segments may not be modified}}

  do_catchsql_test 16.20 {
    DROP TABLE y1_segments;
  } {1 {table y1_segments may not be dropped}}

  do_catchsql_test 16.21 {
    ALTER TABLE y1_segments RENAME TO abc;
  } {1 {table y1_segments may not be altered}}
  sqlite3_db_config db DEFENSIVE 0
  do_catchsql_test 16.22 {
    ALTER TABLE y1_segments RENAME TO abc;
  } {0 {}}
  sqlite3_db_config db DEFENSIVE 1
................................................................................
  } {1 {object name reserved for internal use: y1_segments}}
  sqlite3_db_config db DEFENSIVE 0
  do_catchsql_test 16.25 {
    ALTER TABLE abc RENAME TO y1_segments;
  } {0 {}}
  sqlite3_db_config db DEFENSIVE 1

  do_catchsql_test 16.21 {
    DROP TABLE y1_segments;
  } {1 {table y1_segments may not be dropped}}

  do_execsql_test 16.30 {
    ALTER TABLE y1 RENAME TO z1;
  }

  do_execsql_test 16.40 {
    SELECT * FROM z1_segments;
  }

Changes to test/attach.test.

759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775


776
777
778
779
780
781
782

783
784
785
786
787
788
789
#
do_test attach-6.1 {
  catchsql {
    ATTACH DATABASE 'no-such-file' AS nosuch;
  }
} {0 {}}
if {$tcl_platform(platform)=="unix"} {
  do_test attach-6.2 {
    sqlite3 dbx cannot-read
    dbx eval {CREATE TABLE t1(a,b,c)}
    dbx close
    file attributes cannot-read -permission 0000
    if {[file writable cannot-read]} {
      puts "\n**** Tests do not work when run as root ****"
      forcedelete cannot-read
      exit 1
    }


    catchsql {
      ATTACH DATABASE 'cannot-read' AS noread;
    }
  } {1 {unable to open database: cannot-read}}
  do_test attach-6.2.2 {
    db errorcode
  } {14}

  forcedelete cannot-read
}

# Check the error message if we try to access a database that has
# not been attached.
do_test attach-6.3 {
  catchsql {







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







759
760
761
762
763
764
765

766
767
768
769
770
771
772
773

774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
#
do_test attach-6.1 {
  catchsql {
    ATTACH DATABASE 'no-such-file' AS nosuch;
  }
} {0 {}}
if {$tcl_platform(platform)=="unix"} {

  sqlite3 dbx cannot-read
  dbx eval {CREATE TABLE t1(a,b,c)}
  dbx close
  file attributes cannot-read -permission 0000
  if {[file writable cannot-read]} {
    #puts "\n**** Tests do not work when run as root ****"
    forcedelete cannot-read
    #exit 1

  } else {
    do_test attach-6.2 {
      catchsql {
        ATTACH DATABASE 'cannot-read' AS noread;
      }
    } {1 {unable to open database: cannot-read}}
    do_test attach-6.2.2 {
      db errorcode
    } {14}
  }
  forcedelete cannot-read
}

# Check the error message if we try to access a database that has
# not been attached.
do_test attach-6.3 {
  catchsql {

Changes to test/attach4.test.

76
77
78
79
80
81
82

83
84
85
86
87
88
89
foreach {name f} $files {
  if {[permutation] == "journaltest"} {
    set mode delete
  } else {
    set mode wal
  }
  ifcapable !wal { set mode delete }

  lappend L $mode
  append S "
    PRAGMA $name.journal_mode = WAL;
    UPDATE $name.tbl SET x = '$name';
  "
}
do_execsql_test 1.5 $S $L







>







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
foreach {name f} $files {
  if {[permutation] == "journaltest"} {
    set mode delete
  } else {
    set mode wal
  }
  ifcapable !wal { set mode delete }
  if ![wal_is_ok] { set mode delete }
  lappend L $mode
  append S "
    PRAGMA $name.journal_mode = WAL;
    UPDATE $name.tbl SET x = '$name';
  "
}
do_execsql_test 1.5 $S $L

Changes to test/bind.test.

652
653
654
655
656
657
658



659
660
661
662
663
664
665
  sqlite3_reset $VM
  sqlite3_clear_bindings $VM
  sqlite3_step $VM
  list [sqlite3_column_type $VM 0] [sqlite3_column_type $VM 1] \
               [sqlite3_column_type $VM 2]
} {NULL NULL NULL}
sqlite3_finalize $VM




#--------------------------------------------------------------------
# These tests attempt to reproduce bug #3463.
#
proc param_names {db zSql} {
  set ret [list]
  set VM [sqlite3_prepare db $zSql -1 TAIL]







>
>
>







652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  sqlite3_reset $VM
  sqlite3_clear_bindings $VM
  sqlite3_step $VM
  list [sqlite3_column_type $VM 0] [sqlite3_column_type $VM 1] \
               [sqlite3_column_type $VM 2]
} {NULL NULL NULL}
sqlite3_finalize $VM
do_test bind-13.5 {
  sqlite3_clear_bindings_null
} {0}

#--------------------------------------------------------------------
# These tests attempt to reproduce bug #3463.
#
proc param_names {db zSql} {
  set ret [list]
  set VM [sqlite3_prepare db $zSql -1 TAIL]

Changes to test/cache.test.

103
104
105
106
107
108
109


110
111
112
113
114


115

116
117
118
119
120
121
122
...
126
127
128
129
130
131
132


133

134
135
136


137

138
139
140
do_test cache-2.3.2 { pager_cache_size db } 2
do_execsql_test cache-2.3.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.3.4 { pager_cache_size db } 2
do_execsql_test cache-2.3.5 COMMIT


do_test cache-2.3.6 { pager_cache_size db } 1

do_execsql_test cache-2.3.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}


do_test cache-2.3.8 { pager_cache_size db } 1


# Tests for cache_size = 0.
#
do_execsql_test cache-2.4.1 {
  PRAGMA cache_size = 0;
  BEGIN;
    INSERT INTO t1 VALUES(1, 2);
................................................................................
do_execsql_test cache-2.4.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.4.4 { pager_cache_size db } 2
do_execsql_test cache-2.4.5 COMMIT



do_test cache-2.4.6 { pager_cache_size db } 0

do_execsql_test cache-2.4.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}


do_test cache-2.4.8 { pager_cache_size db } 0


sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
finish_test







>
>
|
|



>
>
|
>







 







>
>
|
>



>
>
|
>



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
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
do_test cache-2.3.2 { pager_cache_size db } 2
do_execsql_test cache-2.3.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.3.4 { pager_cache_size db } 2
do_execsql_test cache-2.3.5 COMMIT
if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.3.6 { pager_cache_size db } 1
}
do_execsql_test cache-2.3.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}
if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.3.8 { pager_cache_size db } 1
}

# Tests for cache_size = 0.
#
do_execsql_test cache-2.4.1 {
  PRAGMA cache_size = 0;
  BEGIN;
    INSERT INTO t1 VALUES(1, 2);
................................................................................
do_execsql_test cache-2.4.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.4.4 { pager_cache_size db } 2
do_execsql_test cache-2.4.5 COMMIT

if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.4.6 { pager_cache_size db } 0
}
do_execsql_test cache-2.4.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}
if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.4.8 { pager_cache_size db } 0
}

sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
finish_test

Changes to test/dbstatus2.test.

38
39
40
41
42
43
44



45
46
47
48
49
50
51
}

proc db_spill {db {reset 0}} {
  sqlite3_db_status $db CACHE_SPILL $reset
}

do_test 1.1 {



  db close
  sqlite3 db test.db
  execsql { PRAGMA mmap_size = 0 }
  expr {[file size test.db] / 1024}
} 6

do_test 1.2 {







>
>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
}

proc db_spill {db {reset 0}} {
  sqlite3_db_status $db CACHE_SPILL $reset
}

do_test 1.1 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  sqlite3 db test.db
  execsql { PRAGMA mmap_size = 0 }
  expr {[file size test.db] / 1024}
} 6

do_test 1.2 {

Changes to test/e_wal.test.

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
#
# 1.1: "create" tests.
# 1.2: "read" tests.
# 1.3: "write" tests.
#
# All three done with VFS "oldvfs", which has iVersion==1 and so does
# not support shared memory.
# 

sqlite3 db test.db -vfs oldvfs
do_execsql_test 1.1.1 {
  PRAGMA journal_mode = WAL;
} {delete}
do_execsql_test 1.1.2 {
  PRAGMA locking_mode = EXCLUSIVE;
  PRAGMA journal_mode = WAL;







|
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#
# 1.1: "create" tests.
# 1.2: "read" tests.
# 1.3: "write" tests.
#
# All three done with VFS "oldvfs", which has iVersion==1 and so does
# not support shared memory.
#
forcedelete test.db-shm
sqlite3 db test.db -vfs oldvfs
do_execsql_test 1.1.1 {
  PRAGMA journal_mode = WAL;
} {delete}
do_execsql_test 1.1.2 {
  PRAGMA locking_mode = EXCLUSIVE;
  PRAGMA journal_mode = WAL;

Changes to test/e_walckpt.test.

436
437
438
439
440
441
442

443
444
445
446
447
448
449
      #
      # EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
      # in the SQLITE_CHECKPOINT_PASSIVE mode.
      #
      #   It's not. Test case "$tp.6".
      #
      do_test $tp.4 {

        forcecopy test.db abc.db
        sqlite3 db4 abc.db
        db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 }
      } {1 2 3 4 5 6}
      do_test $tp.5 { set ::sync_counter } 0
      do_test $tp.6 { set ::busy_handler_counter } 0
      db4 close







>







436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
      #
      # EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
      # in the SQLITE_CHECKPOINT_PASSIVE mode.
      #
      #   It's not. Test case "$tp.6".
      #
      do_test $tp.4 {
        forcedelete abc.db-shm abc.db-wal       
        forcecopy test.db abc.db
        sqlite3 db4 abc.db
        db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 }
      } {1 2 3 4 5 6}
      do_test $tp.5 { set ::sync_counter } 0
      do_test $tp.6 { set ::busy_handler_counter } 0
      db4 close

Changes to test/exclusive.test.

400
401
402
403
404
405
406
407
408
409
410
411
412

413
414
415
416
417
418
419
#
db close
sqlite3 db test.db

# if we're using proxy locks, we use 3 filedescriptors for a db
# that is open but NOT writing changes, normally
# sqlite uses 1 (proxy locking adds the conch and the local lock)
set using_proxy 0
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
  set using_proxy $value
}
set extrafds 0
if {$using_proxy!=0} {

  set extrafds 2
} 

do_test exclusive-5.0 {
  execsql {
    CREATE TABLE abc(a UNIQUE, b UNIQUE, c UNIQUE);
    BEGIN;







<
<
<
<

<
>







400
401
402
403
404
405
406




407

408
409
410
411
412
413
414
415
#
db close
sqlite3 db test.db

# if we're using proxy locks, we use 3 filedescriptors for a db
# that is open but NOT writing changes, normally
# sqlite uses 1 (proxy locking adds the conch and the local lock)




set extrafds 0

if {[forced_proxy_locking]} {
  set extrafds 2
} 

do_test exclusive-5.0 {
  execsql {
    CREATE TABLE abc(a UNIQUE, b UNIQUE, c UNIQUE);
    BEGIN;

Changes to test/fallocate.test.

84
85
86
87
88
89
90

91
92
93
94








95
96


97

98
99
100
101
102
103
104
# The following tests - fallocate-2.* - test that things work in WAL
# mode as well.
#
set skipwaltests [expr {
  [permutation]=="journaltest" || [permutation]=="inmemory_journal"
}]
ifcapable !wal { set skipwaltests 1 }


if {!$skipwaltests} {
  db close
  forcedelete test.db








  sqlite3 db test.db
  file_control_chunksize_test db main [expr 32*1024]


  

  do_test fallocate-2.1 {
    execsql {
      PRAGMA page_size = 1024;
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(a, b);
    }
    file size test.db







>




>
>
>
>
>
>
>
>

<
>
>
|
>







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
# The following tests - fallocate-2.* - test that things work in WAL
# mode as well.
#
set skipwaltests [expr {
  [permutation]=="journaltest" || [permutation]=="inmemory_journal"
}]
ifcapable !wal { set skipwaltests 1 }
if {![wal_is_ok]} { set skipwaltests 1 }

if {!$skipwaltests} {
  db close
  forcedelete test.db
  ifcapable enable_persist_wal {
    forcedelete test.db-journal
    forcedelete test.db-wal
    forcedelete test.db-shm
  }
  if {[forced_proxy_locking]} { 
    forcedelete .test.db-conch
  }
  sqlite3 db test.db

  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  file_control_chunksize_test db main [expr 32*1024]
  do_test fallocate-2.1 {
    execsql {
      PRAGMA page_size = 1024;
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(a, b);
    }
    file size test.db

Changes to test/filter1.test.

159
160
161
162
163
164
165




















166
167
168
169
170
171
172
} {2.0 5.0 10.0}
do_execsql_test 4.3 {
  SELECT a, avg(c) FILTER (WHERE b!=1) AS h FROM t1 GROUP BY a ORDER BY avg(c);
} {c 2.0 a 10.0 b 5.0}
do_execsql_test 4.4 {
  SELECT a, avg(c) FILTER (WHERE b!=1) FROM t1 GROUP BY a ORDER BY 2
} {c 2.0 b 5.0 a 10.0}





















#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(1, 3);







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







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
} {2.0 5.0 10.0}
do_execsql_test 4.3 {
  SELECT a, avg(c) FILTER (WHERE b!=1) AS h FROM t1 GROUP BY a ORDER BY avg(c);
} {c 2.0 a 10.0 b 5.0}
do_execsql_test 4.4 {
  SELECT a, avg(c) FILTER (WHERE b!=1) FROM t1 GROUP BY a ORDER BY 2
} {c 2.0 b 5.0 a 10.0}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(1, 3);
}

do_execsql_test 5.1 {
  SELECT count(*) FILTER (WHERE b>2) FROM (SELECT * FROM t1) 
} {1}

do_execsql_test 5.2 {
  SELECT count(*) FILTER (WHERE b>2) OVER () FROM (SELECT * FROM t1) 
} {1 1}

do_execsql_test 5.3 {
  SELECT count(*) FILTER (WHERE b>2) OVER (ORDER BY b) FROM (SELECT * FROM t1) 
} {0 1}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(1, 3);

Changes to test/incrblob3.test.

256
257
258
259
260
261
262




263
264
265
266
267
268

269
270
271
  set dbversion [hexio_get_int [hexio_read test.db 24 4]]
  incr dbversion
  hexio_write test.db 24 [hexio_render_int32 $dbversion]

  return ""
}





do_test incrblob3-7.2 {
  sqlite3 db test.db 
  sqlite3_db_config_lookaside db 0 0 0
  list [catch {db incrblob blobs v 1} msg] $msg
} {1 {database schema has changed}}
db close

tvfs delete

finish_test







>
>
>
>
|
|
|
|
|
|
>



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  set dbversion [hexio_get_int [hexio_read test.db 24 4]]
  incr dbversion
  hexio_write test.db 24 [hexio_render_int32 $dbversion]

  return ""
}

#set sqlite_os_trace 1
# AFP asserts because the "db incrblob blobs v 1" clears the file locks and the unlock fails (HFS doesn't care about a failed unlock)
if {[path_is_local "."]} {

  do_test incrblob3-7.2 {
    sqlite3 db test.db 
    sqlite3_db_config_lookaside db 0 0 0
    list [catch {db incrblob blobs v 1} msg] $msg
  } {1 {database schema has changed}}
  db close
}
tvfs delete

finish_test

Changes to test/incrvacuum2.test.

11
12
13
14
15
16
17

18
19
20
21
22
23
24
...
129
130
131
132
133
134
135


136
137
138
139
140
141
142
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the incremental vacuum feature.
#
# $Id: incrvacuum2.test,v 1.6 2009/07/25 13:42:50 danielk1977 Exp $

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


# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum || !pragma} {
  finish_test
  return
}
................................................................................
    DELETE FROM abc;
    PRAGMA incremental_vacuum;
    COMMIT;
  }
} {}

integrity_check incrvacuum2-3.3



if {[wal_is_capable]} {
  # At one point, when a specific page was being extracted from the b-tree
  # free-list (e.g. during an incremental-vacuum), all trunk pages that
  # occurred before the specific page in the free-list trunk were being
  # written to the journal or wal file. This is not necessary. Only the 
  # extracted page and the page that contains the pointer to it need to







>







 







>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the incremental vacuum feature.
#
# $Id: incrvacuum2.test,v 1.6 2009/07/25 13:42:50 danielk1977 Exp $

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

# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum || !pragma} {
  finish_test
  return
}
................................................................................
    DELETE FROM abc;
    PRAGMA incremental_vacuum;
    COMMIT;
  }
} {}

integrity_check incrvacuum2-3.3

if ![wal_is_ok] { finish_test; return }

if {[wal_is_capable]} {
  # At one point, when a specific page was being extracted from the b-tree
  # free-list (e.g. during an incremental-vacuum), all trunk pages that
  # occurred before the specific page in the free-list trunk were being
  # written to the journal or wal file. This is not necessary. Only the 
  # extracted page and the page that contains the pointer to it need to

Changes to test/join.test.

879
880
881
882
883
884
885





















886
887
888
889
890
891
892
  INSERT INTO t1(x) VALUES(0),(1);
  SELECT * FROM t1 LEFT JOIN (SELECT abs(1) AS y FROM t1) ON x WHERE NOT(y='a');
} {1 1 1 1}
do_execsql_test join-17.110 {
  SELECT * FROM t1 LEFT JOIN (SELECT abs(1)+2 AS y FROM t1) ON x
   WHERE NOT(y='a');
} {1 3 1 3}






















#-------------------------------------------------------------------------
reset_db
do_execsql_test join-18.1 {
  CREATE TABLE t0(a);
  CREATE TABLE t1(b);
  CREATE VIEW v0 AS SELECT a FROM t1 LEFT JOIN t0;







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







879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
  INSERT INTO t1(x) VALUES(0),(1);
  SELECT * FROM t1 LEFT JOIN (SELECT abs(1) AS y FROM t1) ON x WHERE NOT(y='a');
} {1 1 1 1}
do_execsql_test join-17.110 {
  SELECT * FROM t1 LEFT JOIN (SELECT abs(1)+2 AS y FROM t1) ON x
   WHERE NOT(y='a');
} {1 3 1 3}

#-------------------------------------------------------------------------
reset_db
do_execsql_test join-18.1 {
  CREATE TABLE t0(a);
  CREATE TABLE t1(b);
  CREATE VIEW v0 AS SELECT a FROM t1 LEFT JOIN t0;
  INSERT INTO t1 VALUES (1);
} {}

do_execsql_test join-18.2 {
  SELECT * FROM v0 WHERE NOT(v0.a IS FALSE);
} {{}}

do_execsql_test join-18.3 {
  SELECT * FROM t1 LEFT JOIN t0 WHERE NOT(a IS FALSE);
} {1 {}}

do_execsql_test join-18.4 {
  SELECT NOT(v0.a IS FALSE) FROM v0
} {1}

#-------------------------------------------------------------------------
reset_db
do_execsql_test join-18.1 {
  CREATE TABLE t0(a);
  CREATE TABLE t1(b);
  CREATE VIEW v0 AS SELECT a FROM t1 LEFT JOIN t0;

Changes to test/journal3.test.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl

#-------------------------------------------------------------------------
# If a connection is required to create a journal file, it creates it with 
# the same file-system permissions as the database file itself. Test this.
#
if {$::tcl_platform(platform) == "unix"
 && [atomic_batch_write test.db]==0
} {

  # Changed on 2012-02-13:  umask is deliberately ignored for -wal, -journal,
  # and -shm files.
  #set umask [exec /bin/sh -c umask]
  faultsim_delete_and_reopen







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl

#-------------------------------------------------------------------------
# If a connection is required to create a journal file, it creates it with 
# the same file-system permissions as the database file itself. Test this.
#
if {$::tcl_platform(platform) == "unix" && ![path_is_dos "."]
 && [atomic_batch_write test.db]==0
} {

  # Changed on 2012-02-13:  umask is deliberately ignored for -wal, -journal,
  # and -shm files.
  #set umask [exec /bin/sh -c umask]
  faultsim_delete_and_reopen

Changes to test/lock5.test.

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

forcedelete test.db
if {[catch {sqlite3 db test.db -vfs unix-flock} msg]} {
  finish_test
  return
}




do_test lock5-flock.1 {
  sqlite3 db test.db -vfs unix-flock
  execsql {
    CREATE TABLE t1(a, b);
    BEGIN;
    INSERT INTO t1 VALUES(1, 2);
  }
} {}

# Make sure we are not accidentally using the dotfile locking scheme.
do_test lock5-flock.2 {
  file exists test.db.lock
} {0}

do_test lock5-flock.3 {
  catch { sqlite3 db2 test.db -vfs unix-flock }
  catchsql { SELECT * FROM t1 } db2
} {1 {database is locked}}

do_test lock5-flock.4 {
  execsql COMMIT
  catchsql { SELECT * FROM t1 } db2
} {0 {1 2}}

do_test lock5-flock.5 {
  execsql BEGIN
  catchsql { SELECT * FROM t1 } db2
} {0 {1 2}}

do_test lock5-flock.6 {
  execsql {SELECT * FROM t1}
  catchsql { SELECT * FROM t1 } db2
} {1 {database is locked}}

do_test lock5-flock.7 {
  db close
  catchsql { SELECT * FROM t1 } db2
} {0 {1 2}}

do_test lock5-flock.8 {
  db2 close
} {}

#####################################################################

do_test lock5-none.1 {
  sqlite3 db test.db -vfs unix-none
  sqlite3 db2 test.db -vfs unix-none
  execsql { PRAGMA mmap_size = 0 } db2
  execsql {
    BEGIN;
    INSERT INTO t1 VALUES(3, 4);
  }
} {}
do_test lock5-none.2 {
  execsql { SELECT * FROM t1 }
} {1 2 3 4}
do_test lock5-none.3 {
  execsql { SELECT * FROM t1; } db2
} {1 2}
do_test lock5-none.4 {
  execsql { 
    BEGIN;
    SELECT * FROM t1;
  } db2
} {1 2}
do_test lock5-none.5 {
  execsql COMMIT



  execsql {SELECT * FROM t1} db2
} {1 2}

ifcapable memorymanage {
  do_test lock5-none.6 {
    sqlite3_release_memory 1000000
    execsql {SELECT * FROM t1} db2
  } {1 2 3 4}
}

do_test lock5-none.X {
  db close
  db2 close
} {}


ifcapable lock_proxy_pragmas {
  set env(SQLITE_FORCE_PROXY_LOCKING) $::using_proxy
}

finish_test







>
>
>
|
|
|
|
|
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|

|
|
|

|

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

|
|
|
|
|
|

|
|
|
|
>






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

forcedelete test.db
if {[catch {sqlite3 db test.db -vfs unix-flock} msg]} {
  finish_test
  return
}

# Only run the flock tests on a local file system
if { [path_is_local "."] } {

  do_test lock5-flock.1 {
    sqlite3 db test.db -vfs unix-flock
    execsql {
      CREATE TABLE t1(a, b);
      BEGIN;
      INSERT INTO t1 VALUES(1, 2);
    }
  } {}

  # Make sure we are not accidentally using the dotfile locking scheme.
  do_test lock5-flock.2 {
    file exists test.db.lock
  } {0}

  do_test lock5-flock.3 {
    catch { sqlite3 db2 test.db -vfs unix-flock }
    catchsql { SELECT * FROM t1 } db2
  } {1 {database is locked}}

  do_test lock5-flock.4 {
    execsql COMMIT
    catchsql { SELECT * FROM t1 } db2
  } {0 {1 2}}

  do_test lock5-flock.5 {
    execsql BEGIN
    catchsql { SELECT * FROM t1 } db2
  } {0 {1 2}}

  do_test lock5-flock.6 {
    execsql {SELECT * FROM t1}
    catchsql { SELECT * FROM t1 } db2
  } {1 {database is locked}}

  do_test lock5-flock.7 {
    db close
    catchsql { SELECT * FROM t1 } db2
  } {0 {1 2}}

  do_test lock5-flock.8 {
    db2 close
  } {}

  #####################################################################

  do_test lock5-none.1 {
    sqlite3 db test.db -vfs unix-none
    sqlite3 db2 test.db -vfs unix-none

    execsql {
      BEGIN;
      INSERT INTO t1 VALUES(3, 4);
    }
  } {}
  do_test lock5-none.2 {
    execsql { SELECT * FROM t1 }
  } {1 2 3 4}
  do_test lock5-flock.3 {
    execsql { SELECT * FROM t1 } db2
  } {1 2}
  do_test lock5-none.4 {
    execsql { 
      BEGIN;
      SELECT * FROM t1;
    } db2
  } {1 2}
  do_test lock5-none.5 {
    execsql COMMIT
  } {}
  do_test lock5-none.6 {
    sqlite3_release_memory 1000000
    execsql {SELECT * FROM t1} db2
  } {1 2}

  ifcapable memorymanage {
    do_test lock5-none.6 {
      sqlite3_release_memory 1000000
      execsql {SELECT * FROM t1} db2
    } {1 2 3 4}
  }

  do_test lock5-flock.X {
    db close
    db2 close
  } {}
}

ifcapable lock_proxy_pragmas {
  set env(SQLITE_FORCE_PROXY_LOCKING) $::using_proxy
}

finish_test

Changes to test/lock6.test.

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
    set lockpath [execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db]
    set lockpath
  } {{:auto: (not held)}}


  do_test lock6-1.4.1 {

    catchsql {
      PRAGMA lock_proxy_file="notmine";
      select * from sqlite_master;
    } db
  } {1 {database is locked}}

  do_test lock6-1.4.2 {
    execsql {
      PRAGMA lock_proxy_file;
    } db
  } {notmine}
    
  do_test lock6-1.5 {
    testfixture $::tf1 {
      db eval {
        BEGIN;
        SELECT * FROM sqlite_master;
      }
    }
  } {}

  catch {testfixture $::tf1 {db close}}


  do_test lock6-1.6 {

    execsql {
      PRAGMA lock_proxy_file="mine";
      select * from sqlite_master;
    } db
  } {}
  
  catch {close $::tf1}
  set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
  set sqlite_hostid_num 0

  sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
}
      
finish_test







>

>

<








|












>

>

<












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
    set lockpath [execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db]
    set lockpath
  } {{:auto: (not held)}}

  set lpp [exec mktemp -t fail]
  do_test lock6-1.4.1 {
    execsql "PRAGMA lock_proxy_file='$lpp'"
    catchsql {

      select * from sqlite_master;
    } db
  } {1 {database is locked}}

  do_test lock6-1.4.2 {
    execsql {
      PRAGMA lock_proxy_file;
    } db
  } $lpp
    
  do_test lock6-1.5 {
    testfixture $::tf1 {
      db eval {
        BEGIN;
        SELECT * FROM sqlite_master;
      }
    }
  } {}

  catch {testfixture $::tf1 {db close}}

  set lpp [exec mktemp -t ok]
  do_test lock6-1.6 {
    execsql "PRAGMA lock_proxy_file='$lpp'"
    execsql {

      select * from sqlite_master;
    } db
  } {}
  
  catch {close $::tf1}
  set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
  set sqlite_hostid_num 0

  sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
}
      
finish_test

Added test/lock_proxy.test.





























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
# 2008 June 28
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is database proxy locks.
#
# $Id$

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

# This file is only run if using the unix backend compiled with the
# SQLITE_ENABLE_LOCKING_STYLE macro.
db close
if {[catch {sqlite3 db test.db -vfs unix-none} msg]} {
  finish_test
  return
}
db close
file delete -force test.db.lock

#####################################################################
ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
  set ::using_proxy 0
  foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
    set ::using_proxy $value
  }

  # enable the proxy locking for these tests
  set env(SQLITE_FORCE_PROXY_LOCKING) "1"

  # test conch file creation
  #

  catch { file delete lock_proxy_test.db }
  catch { file delete .lock_proxy_test.db-conch }
  # test that proxy locking mode creates conch files
  do_test lock_proxy1.0 {
    sqlite3 db2 lock_proxy_test.db
    catchsql {
      create table x(y);
    } db2
    file exists .lock_proxy_test.db-conch
  } {1}
  catch { db2 close }


  # test proxy locking readonly file system handling
  #

  if {[file exists /usr/bin/hdiutil]} {

    puts "Creating readonly file system for proxy locking tests..."
    if {[file exists /Volumes/readonly]} {
      exec hdiutil detach /Volumes/readonly
    }
    if {[file exists readonly.dmg]} {
      file delete readonly.dmg
    }
    exec hdiutil create -megabytes 1 -fs HFS+ readonly.dmg -volname readonly
    exec hdiutil attach readonly.dmg

    # create test1.db and a .test1.db-conch for host4
    set sqlite_hostid_num 4
    sqlite3 db2 /Volumes/readonly/test1.db 
    execsql {
      create table x(y);
    } db2
    db2 close

    # create test2.db and a .test2.db-conch for host5
    set sqlite_hostid_num 5
    sqlite3 db2 /Volumes/readonly/test2.db 
    execsql {
      create table x(y);
    } db2
    db2 close

    # create test3.db without a conch file
    set env(SQLITE_FORCE_PROXY_LOCKING) "0"
    sqlite3 db2 /Volumes/readonly/test3.db 
    execsql {
      create table x(y);
    } db2
    db2 close
    exec hdiutil detach /Volumes/readonly
    exec hdiutil attach -readonly readonly.dmg

    # test that an unwritable, host-mismatched conch file prevents 
    # read only proxy-locking mode database access
    set env(SQLITE_FORCE_PROXY_LOCKING) "1"
    do_test lock_proxy2.0 {
      sqlite3 db2 /Volumes/readonly/test1.db
      catchsql {
        select * from sqlite_master;
      } db2
    } {1 {database is locked}}
    catch { db2 close }
    
    # test that an unwritable, host-matching conch file allows
    # read only proxy-locking mode database access
    do_test lock_proxy2.1 {
      sqlite3 db2 /Volumes/readonly/test2.db
      catchsql {
        select * from sqlite_master;
      } db2
    } {0 {table x x 2 {CREATE TABLE x(y)}}}
    catch { db2 close }

    # test that an unwritable, nonexistant conch file allows
    # read only proxy-locking mode database access
    do_test lock_proxy2.2 {
      sqlite3 db2 /Volumes/readonly/test3.db
      catchsql {
        select * from sqlite_master;
      } db2
    } {0 {table x x 2 {CREATE TABLE x(y)}}}
    catch { db2 close }

    exec hdiutil detach /Volumes/readonly
    file delete readonly.dmg
  }
  set env(SQLITE_FORCE_PROXY_LOCKING) "0"
  set sqlite_hostid_num 0
}

#####################################################################

file delete -force test.db

ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
  set env(SQLITE_FORCE_PROXY_LOCKING) $::using_proxy
}

finish_test

Changes to test/main.test.

310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  } {0 {}}
}

# Here are some tests for tokenize.c.  
#
do_test main-3.1 {
  catch {db close}
  foreach f [glob -nocomplain testdb/*] {forcedelete $f}
  forcedelete testdb
  sqlite3 db testdb
  set v [catch {execsql {SELECT * from T1 where x!!5}} msg]
  lappend v $msg
} {1 {unrecognized token: "!"}}
do_test main-3.2 {
  catch {db close}
  foreach f [glob -nocomplain testdb/*] {forcedelete $f}
  forcedelete testdb
  sqlite3 db testdb
  set v [catch {execsql {SELECT * from T1 where ^x}} msg]
  lappend v $msg
} {1 {unrecognized token: "^"}}
do_test main-3.2.2 {
  catchsql {select 'abc}
................................................................................
do_test main-3.2.30 {
  catchsql {select 123--5}
} {0 123}


do_test main-3.3 {
  catch {db close}
  foreach f [glob -nocomplain testdb/*] {forcedelete $f}
  forcedelete testdb
  sqlite3 db testdb
  execsql {
    create table T1(X REAL);  /* C-style comments allowed */
    insert into T1 values(0.5);
    insert into T1 values(0.5e2);
    insert into T1 values(0.5e-002);







|







|







 







|







310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  } {0 {}}
}

# Here are some tests for tokenize.c.  
#
do_test main-3.1 {
  catch {db close}
  catch {foreach f [glob -nocomplain testdb/*] {forcedelete $f}}
  forcedelete testdb
  sqlite3 db testdb
  set v [catch {execsql {SELECT * from T1 where x!!5}} msg]
  lappend v $msg
} {1 {unrecognized token: "!"}}
do_test main-3.2 {
  catch {db close}
  catch {foreach f [glob -nocomplain testdb/*] {forcedelete $f}}
  forcedelete testdb
  sqlite3 db testdb
  set v [catch {execsql {SELECT * from T1 where ^x}} msg]
  lappend v $msg
} {1 {unrecognized token: "^"}}
do_test main-3.2.2 {
  catchsql {select 'abc}
................................................................................
do_test main-3.2.30 {
  catchsql {select 123--5}
} {0 123}


do_test main-3.3 {
  catch {db close}
  catch {foreach f [glob -nocomplain testdb/*] {forcedelete $f}}
  forcedelete testdb
  sqlite3 db testdb
  execsql {
    create table T1(X REAL);  /* C-style comments allowed */
    insert into T1 values(0.5);
    insert into T1 values(0.5e2);
    insert into T1 values(0.5e-002);

Changes to test/malloc_common.tcl.

441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
      # fails and then subsequent calls succeed. If $::iRepeat is 1, 
      # then the failure is persistent - once malloc() fails it keeps
      # failing.
      #
      set zRepeat "transient"
      if {$::iRepeat} {set zRepeat "persistent"}
      restore_prng_state
      foreach file [glob -nocomplain test.db-mj*] {forcedelete $file}

      do_test ${tn}.${zRepeat}.${::n} {
  
        # Remove all traces of database files test.db and test2.db 
        # from the file-system. Then open (empty database) "test.db" 
        # with the handle [db].
        # 







|







441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
      # fails and then subsequent calls succeed. If $::iRepeat is 1, 
      # then the failure is persistent - once malloc() fails it keeps
      # failing.
      #
      set zRepeat "transient"
      if {$::iRepeat} {set zRepeat "persistent"}
      restore_prng_state
      catch {foreach file [glob -nocomplain test.db-mj*] {forcedelete $file}}

      do_test ${tn}.${zRepeat}.${::n} {
  
        # Remove all traces of database files test.db and test2.db 
        # from the file-system. Then open (empty database) "test.db" 
        # with the handle [db].
        # 

Changes to test/manydb.test.

18
19
20
21
22
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
set testdir [file dirname $argv0]
source $testdir/tester.tcl

set N 300
# if we're using proxy locks, we use 5 filedescriptors for a db
# that is open and in the middle of writing changes, normally
# sqlite uses 3 (proxy locking adds the conch and the local lock)
set using_proxy 0
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
  set using_proxy value
}
set num_fd_per_openwrite_db 3
if {$using_proxy>0} {

  set num_fd_per_openwrite_db 5
} 

# First test how many file descriptors are available for use. To open a
# database for writing SQLite requires 3 file descriptors (the database, the
# journal and the directory).
set filehandles {}







<
<
<
<

<
>







18
19
20
21
22
23
24




25

26
27
28
29
30
31
32
33
set testdir [file dirname $argv0]
source $testdir/tester.tcl

set N 300
# if we're using proxy locks, we use 5 filedescriptors for a db
# that is open and in the middle of writing changes, normally
# sqlite uses 3 (proxy locking adds the conch and the local lock)




set num_fd_per_openwrite_db 3

if {[forced_proxy_locking]} {
  set num_fd_per_openwrite_db 5
} 

# First test how many file descriptors are available for use. To open a
# database for writing SQLite requires 3 file descriptors (the database, the
# journal and the directory).
set filehandles {}

Changes to test/memdb.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
403
404
405
406
407
408
409


410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

427
428
429
430
431
#    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 in-memory database backend.
#
# $Id: memdb.test,v 1.19 2009/05/18 16:04:38 danielk1977 Exp $


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

ifcapable memorydb {

................................................................................
    DELETE FROM t1;
    SELECT count(*) FROM t1;
  }
} 0

# Test that auto-vacuum works with in-memory databases.
# 


ifcapable autovacuum {
  do_test memdb-9.1 {
    db close
    sqlite3 db test.db
    db cache size 0
    execsql {
      PRAGMA auto_vacuum = full;
      CREATE TABLE t1(a);
      INSERT INTO t1 VALUES(randstr(1000,1000));
      INSERT INTO t1 VALUES(randstr(1000,1000));
      INSERT INTO t1 VALUES(randstr(1000,1000));
    }
    set before [db one {PRAGMA page_count}]
    execsql { DELETE FROM t1 }
    set after [db one {PRAGMA page_count}]
    expr {$before>$after}
  } {1}

}

} ;# ifcapable memorydb

finish_test







<







 







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





7
8
9
10
11
12
13

14
15
16
17
18
19
20
...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
#    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 in-memory database backend.
#



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

ifcapable memorydb {

................................................................................
    DELETE FROM t1;
    SELECT count(*) FROM t1;
  }
} 0

# Test that auto-vacuum works with in-memory databases.
# 
set msize [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0]
if {[lindex $msize 2]!=0} {
  ifcapable autovacuum {
    do_test memdb-9.1 {
      db close
      sqlite3 db test.db
      db cache size 0
      execsql {
        PRAGMA auto_vacuum = full;
        CREATE TABLE t1(a);
        INSERT INTO t1 VALUES(randstr(1000,1000));
        INSERT INTO t1 VALUES(randstr(1000,1000));
        INSERT INTO t1 VALUES(randstr(1000,1000));
      }
      set before [db one {PRAGMA page_count}]
      execsql { DELETE FROM t1 }
      set after [db one {PRAGMA page_count}]
      expr {$before>$after}
    } {1}
  }
}

} ;# ifcapable memorydb

finish_test

Changes to test/memsubsys1.test.

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
...
165
166
167
168
169
170
171

172
173
174

175
176
177
178
179
180
181
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 512+$xtra_size] 20
sqlite3_config singlethread
sqlite3_initialize
reset_highwater_marks
build_test_db memsubsys1-3.1 {PRAGMA page_size=1024}

do_test memsubsys1-3.1.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
} 0
do_test memsubsys1-3.1.4 {
  set overflow [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
  # Note:  The measured PAGECACHE_OVERFLOW is amount malloc() returns, not what
  # was requested.  System malloc() implementations might (arbitrarily) return
  # slightly different oversize buffers, which can result in slightly different
  # PAGECACHE_OVERFLOW sizes between consecutive runs.  So we cannot do an
  # exact comparison.  Simply verify that the amount is within 5%.
  expr {$overflow>=$max_pagecache*0.95 && $overflow<=$max_pagecache*1.05}
} 1

do_test memsubsys1-3.1.5 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 0
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 2048+$xtra_size] 20
sqlite3_initialize
................................................................................
reset_highwater_marks
build_test_db memsubsys1-4 {PRAGMA page_size=1024}
#show_memstats
do_test memsubsys1-4.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  expr {$pg_used>=45 && $pg_used<=50}
} 1

do_test memsubsys1-4.4 {
  set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
} 0

do_test memsubsys1-4.5 {
  set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
  expr {$maxreq<7000}
} 1

db close
sqlite3_shutdown







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







 







>
|
|
|
>







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
...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 512+$xtra_size] 20
sqlite3_config singlethread
sqlite3_initialize
reset_highwater_marks
build_test_db memsubsys1-3.1 {PRAGMA page_size=1024}
if !$::sqlite_options(enable_purgeable_pcache) {
  do_test memsubsys1-3.1.3 {
    set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  } 0
  do_test memsubsys1-3.1.4 {
    set overflow [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
    # Note: The measured PAGECACHE_OVERFLOW is amount malloc() returns, not what
    # was requested.  System malloc() implementations might (arbitrarily) return
    # slightly different oversize buffers, which can result in different
    # PAGECACHE_OVERFLOW sizes between consecutive runs.  So we cannot do an
    # exact comparison.  Simply verify that the amount is within 5%.
    expr {$overflow>=$max_pagecache*0.95 && $overflow<=$max_pagecache*1.05}
  } 1
}
do_test memsubsys1-3.1.5 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 0
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 2048+$xtra_size] 20
sqlite3_initialize
................................................................................
reset_highwater_marks
build_test_db memsubsys1-4 {PRAGMA page_size=1024}
#show_memstats
do_test memsubsys1-4.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  expr {$pg_used>=45 && $pg_used<=50}
} 1
if !$::sqlite_options(enable_purgeable_pcache) {
  do_test memsubsys1-4.4 {
    set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
  } 0
}
do_test memsubsys1-4.5 {
  set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
  expr {$maxreq<7000}
} 1

db close
sqlite3_shutdown

Changes to test/multiplex.test.

9
10
11
12
13
14
15






16
17
18
19
20
21
22
#
#***********************************************************************
#

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







# The tests in this file assume that SQLite is compiled without
# ENABLE_8_3_NAMES.
#
ifcapable 8_3_names {
  puts -nonewline "SQLite compiled with SQLITE_ENABLE_8_3_NAMES. "
  puts            "Skipping tests multiplex-*."







>
>
>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#
#***********************************************************************
#

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

# AFP doesn't like multiplex db tests
if { ![path_is_local "."] } {
  finish_test 
  return 
}

# The tests in this file assume that SQLite is compiled without
# ENABLE_8_3_NAMES.
#
ifcapable 8_3_names {
  puts -nonewline "SQLite compiled with SQLITE_ENABLE_8_3_NAMES. "
  puts            "Skipping tests multiplex-*."

Changes to test/pager1.test.

549
550
551
552
553
554
555


556
557
558
559
560
561
562
...
735
736
737
738
739
740
741

742
743
744
745
746
747
748
....
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
....
1252
1253
1254
1255
1256
1257
1258



1259
1260
1261
1262
1263
1264
1265
....
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
....
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
....
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132









2133
2134
2135
2136

2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
....
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
    }
    faultsim_save 
    incr ::mj_delete_cnt
  }
  return SQLITE_OK
}



foreach {tn1 tcl} {
  1 { set prefix "test.db" }
  2 { 
    # This test depends on the underlying VFS being able to open paths
    # 512 bytes in length. The idea is to create a hot-journal file that
    # contains a master-journal pointer so large that it could contain
    # a valid page record (if the file page-size is 512 bytes). So as to
................................................................................
  }

  cd $pwd
}
db close
tv delete
forcedelete $dirname


# Set up a VFS to make a copy of the file-system just before deleting a
# journal file to commit a transaction. The transaction modifies exactly
# two database pages (and page 1 - the change counter).
#
testvfs tv -default 1
tv sectorsize 512
................................................................................
#   $sql: SQL to execute.
#   $res: Expected result of executing $sql.
#   $js:  The expected size of the journal file, in bytes, after executing
#         the SQL script. Or -1 if the journal is not expected to exist.
#   $ws:  The expected size of the WAL file, in bytes, after executing
#         the SQL script. Or -1 if the WAL is not expected to exist.
#
ifcapable wal {
  faultsim_delete_and_reopen
  foreach {tn sql res js ws} [subst {
  
    1  {
      CREATE TABLE t1(a, b);
      PRAGMA auto_vacuum=OFF;
      PRAGMA synchronous=NORMAL;
................................................................................
    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
  
    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
  
  }] {



    do_execsql_test pager1-7.1.$tn.1 $sql $res
    catch { set J -1 ; set J [file size test.db-journal] }
    catch { set W -1 ; set W [file size test.db-wal] }
    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
  }
}

................................................................................
do_test pager1-20.2.2 {
  execsql {
    BEGIN EXCLUSIVE;
    COMMIT;
  }
} {}

ifcapable wal {
  do_test pager1-20.3.1 {
    faultsim_delete_and_reopen
    db func a_string a_string
    execsql {
      PRAGMA cache_size = 10;
      PRAGMA journal_mode = wal;
      BEGIN;
................................................................................

#-------------------------------------------------------------------------
# Test that a WAL database may not be opened if:
#
#   pager1-21.1.*: The VFS has an iVersion less than 2, or
#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
#
ifcapable wal {
  do_test pager1-21.0 {
    faultsim_delete_and_reopen
    execsql {
      PRAGMA journal_mode = WAL;
      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
      INSERT INTO ko DEFAULT VALUES;
    }
................................................................................

#-------------------------------------------------------------------------
# Test that a "PRAGMA wal_checkpoint":
#
#   pager1-22.1.*: is a no-op on a non-WAL db, and
#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
#
ifcapable wal {
  do_test pager1-22.1.1 {
    faultsim_delete_and_reopen
    execsql {
      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
      INSERT INTO ko DEFAULT VALUES;
    }
    execsql { PRAGMA wal_checkpoint }
  } {0 -1 -1}
  do_test pager1-22.2.1 {
    testvfs tv -default 1
    tv filter xSync
    tv script xSyncCb
    proc xSyncCb {args} {incr ::synccount}
    set ::synccount 0
    sqlite3 db test.db









    execsql {
      PRAGMA synchronous = off;
      PRAGMA journal_mode = WAL;
      INSERT INTO ko DEFAULT VALUES;

    }
    execsql { PRAGMA wal_checkpoint }
    set synccount
  } {0}
  db close
  tv delete
}

#-------------------------------------------------------------------------
# Tests for changing journal mode.
#
#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
#                  the journal file is deleted.
#
................................................................................

#-------------------------------------------------------------------------
# Test that attempting to open a write-transaction with 
# locking_mode=exclusive in WAL mode fails if there are other clients on 
# the same database.
#
catch { db close }
ifcapable wal {
  do_multiclient_test tn {
    do_test pager1-28.$tn.1 {
      sql1 { 
        PRAGMA journal_mode = WAL;
        CREATE TABLE t1(a, b);
        INSERT INTO t1 VALUES('a', 'b');
      }







>
>







 







>







 







|







 







>
>
>







 







|







 







|







 







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







 







|







549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
...
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
....
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
....
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
....
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
....
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
....
2116
2117
2118
2119
2120
2121
2122

2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135

2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147

2148
2149
2150

2151
2152



2153
2154
2155
2156
2157
2158
2159
....
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
    }
    faultsim_save 
    incr ::mj_delete_cnt
  }
  return SQLITE_OK
}

if {![forced_proxy_locking]} {
  # proxy locking uses can't deal with auto proxy file paths longer than MAXPATHLEN
foreach {tn1 tcl} {
  1 { set prefix "test.db" }
  2 { 
    # This test depends on the underlying VFS being able to open paths
    # 512 bytes in length. The idea is to create a hot-journal file that
    # contains a master-journal pointer so large that it could contain
    # a valid page record (if the file page-size is 512 bytes). So as to
................................................................................
  }

  cd $pwd
}
db close
tv delete
forcedelete $dirname
}

# Set up a VFS to make a copy of the file-system just before deleting a
# journal file to commit a transaction. The transaction modifies exactly
# two database pages (and page 1 - the change counter).
#
testvfs tv -default 1
tv sectorsize 512
................................................................................
#   $sql: SQL to execute.
#   $res: Expected result of executing $sql.
#   $js:  The expected size of the journal file, in bytes, after executing
#         the SQL script. Or -1 if the journal is not expected to exist.
#   $ws:  The expected size of the WAL file, in bytes, after executing
#         the SQL script. Or -1 if the WAL is not expected to exist.
#
if {$::sqlite_options(wal) && [wal_is_ok]} {
  faultsim_delete_and_reopen
  foreach {tn sql res js ws} [subst {
  
    1  {
      CREATE TABLE t1(a, b);
      PRAGMA auto_vacuum=OFF;
      PRAGMA synchronous=NORMAL;
................................................................................
    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
  
    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
  
  }] {
    ifcapable enable_persist_wal {
      file_control_persist_wal db 0
    }
    do_execsql_test pager1-7.1.$tn.1 $sql $res
    catch { set J -1 ; set J [file size test.db-journal] }
    catch { set W -1 ; set W [file size test.db-wal] }
    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
  }
}

................................................................................
do_test pager1-20.2.2 {
  execsql {
    BEGIN EXCLUSIVE;
    COMMIT;
  }
} {}

if {$::sqlite_options(wal) && [wal_is_ok]} {
  do_test pager1-20.3.1 {
    faultsim_delete_and_reopen
    db func a_string a_string
    execsql {
      PRAGMA cache_size = 10;
      PRAGMA journal_mode = wal;
      BEGIN;
................................................................................

#-------------------------------------------------------------------------
# Test that a WAL database may not be opened if:
#
#   pager1-21.1.*: The VFS has an iVersion less than 2, or
#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
#
if {$::sqlite_options(wal) && [wal_is_ok]} {
  do_test pager1-21.0 {
    faultsim_delete_and_reopen
    execsql {
      PRAGMA journal_mode = WAL;
      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
      INSERT INTO ko DEFAULT VALUES;
    }
................................................................................

#-------------------------------------------------------------------------
# Test that a "PRAGMA wal_checkpoint":
#
#   pager1-22.1.*: is a no-op on a non-WAL db, and
#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
#

do_test pager1-22.1.1 {
  faultsim_delete_and_reopen
  execsql {
    CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
    INSERT INTO ko DEFAULT VALUES;
  }
  execsql { PRAGMA wal_checkpoint }
} {0 -1 -1}
do_test pager1-22.2.1 {
  testvfs tv -default 1
  tv filter xSync
  tv script xSyncCb
  proc xSyncCb {args} {incr ::synccount}

  sqlite3 db test.db

  # Switch the db to WAL mode. And then execute a SELECT to make sure
  # that the WAL file is open. Note that this may change the synchronous
  # setting if DEFAULT_WAL_SAFETYLEVEL is defined.
  execsql { PRAGMA journal_mode = WAL ; SELECT * FROM ko }

  # Set synchronous=OFF. Insert some data and run a checkpoint. Since
  # sync=off, this should not cause any calls to the xSync() method.
  set ::synccount 0
  execsql {
    PRAGMA synchronous = off;

    INSERT INTO ko DEFAULT VALUES;
    PRAGMA wal_checkpoint;
  }

  set synccount
} {0}




#-------------------------------------------------------------------------
# Tests for changing journal mode.
#
#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
#                  the journal file is deleted.
#
................................................................................

#-------------------------------------------------------------------------
# Test that attempting to open a write-transaction with 
# locking_mode=exclusive in WAL mode fails if there are other clients on 
# the same database.
#
catch { db close }
if {$::sqlite_options(wal) && [wal_is_ok]} {
  do_multiclient_test tn {
    do_test pager1-28.$tn.1 {
      sql1 { 
        PRAGMA journal_mode = WAL;
        CREATE TABLE t1(a, b);
        INSERT INTO t1 VALUES('a', 'b');
      }

Changes to test/pagerfault.test.

1057
1058
1059
1060
1061
1062
1063

































1064
1065
1066
1067
1068
1069
1070
      sqlite3 db test.db
      execsql { PRAGMA integrity_check }
    } {ok}
    db close
  }
}



































#-------------------------------------------------------------------------
# When a 3.7.0 client opens a write-transaction on a database file that
# has been appended to or truncated by a pre-370 client, it updates
# the db-size in the file header immediately. This test case provokes
# errors during that operation.
#







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







1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
      sqlite3 db test.db
      execsql { PRAGMA integrity_check }
    } {ok}
    db close
  }
}


#-------------------------------------------------------------------------
# When a 3.7.0 client opens a write-transaction on a database file that
# has been appended to or truncated by a pre-370 client, it updates
# the db-size in the file header immediately. This test case provokes
# errors during that operation.
#
do_test pagerfault-22-pre1 {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA auto_vacuum = 0;
    CREATE TABLE t1(a);
    CREATE INDEX i1 ON t1(a);
    INSERT INTO t1 VALUES(a_string(3000));
    CREATE TABLE t2(a);
    INSERT INTO t2 VALUES(1);
  }
  db close
  sql36231 { INSERT INTO t1 VALUES(a_string(3000)) }
  faultsim_save_and_close
} {}
do_faultsim_test pagerfault-22 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql { INSERT INTO t2 VALUES(2) }
  execsql { SELECT * FROM t2 }
} -test {
  faultsim_test_result {0 {1 2}}
  faultsim_integrity_check
}


#-------------------------------------------------------------------------
# When a 3.7.0 client opens a write-transaction on a database file that
# has been appended to or truncated by a pre-370 client, it updates
# the db-size in the file header immediately. This test case provokes
# errors during that operation.
#

Changes to test/pcache.test.

113
114
115
116
117
118
119
120


121
122
123
124
125
126
127
...
174
175
176
177
178
179
180


181

182
  pcache_stats
} {current 24 max 22 min 20 recyclable 0}

# Rolling back the transaction held by db2 at this point releases a pinned
# page. Because the number of allocated pages is greater than the 
# configured maximum, this page should be freed immediately instead of
# recycled.
#


do_test pcache-1.8 {
  execsql {ROLLBACK} db2
  pcache_stats
} {current 23 max 22 min 20 recyclable 0}

do_test pcache-1.9 {
  execsql COMMIT
................................................................................
    SELECT * FROM t6 ORDER BY a; SELECT * FROM t6;
    SELECT * FROM t7 ORDER BY a; SELECT * FROM t7;
    SELECT * FROM t8 ORDER BY a; SELECT * FROM t8;
    SELECT * FROM t9 ORDER BY a; SELECT * FROM t9;
  }
  pcache_stats
} {current 14 max 15 min 10 recyclable 14}




finish_test







|
>
>







 







>
>
|
>

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
176
177
178
179
180
181
182
183
184
185
186
187
  pcache_stats
} {current 24 max 22 min 20 recyclable 0}

# Rolling back the transaction held by db2 at this point releases a pinned
# page. Because the number of allocated pages is greater than the 
# configured maximum, this page should be freed immediately instead of
# recycled.
# Note- purgable_pcache doesn't share caches between connections and these tests
# are only useful for testing that feature.  
if !$::sqlite_options(enable_purgeable_pcache) {
do_test pcache-1.8 {
  execsql {ROLLBACK} db2
  pcache_stats
} {current 23 max 22 min 20 recyclable 0}

do_test pcache-1.9 {
  execsql COMMIT
................................................................................
    SELECT * FROM t6 ORDER BY a; SELECT * FROM t6;
    SELECT * FROM t7 ORDER BY a; SELECT * FROM t7;
    SELECT * FROM t8 ORDER BY a; SELECT * FROM t8;
    SELECT * FROM t9 ORDER BY a; SELECT * FROM t9;
  }
  pcache_stats
} {current 14 max 15 min 10 recyclable 14}
} else {
  db2 close
}

finish_test

Changes to test/pragma.test.

1526
1527
1528
1529
1530
1531
1532

1533




1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546


1547
1548
1549
1550
1551
1552
1553

1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564

1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586



1587
1588
1589
1590
1591
1592
1593
1594
1595
1596

1597
1598
1599

1600
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618

1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629

1630
1631
1632
1633
1634
1635
1636
1637



1638
1639
1640

1641

1642
1643
1644
1645
1646

1647
1648
1649
1650


1651
1652
1653
1654
1655
1656
1657
1658




























































































1659
1660
1661
1662
1663
1664
1665
}

# Reset the sqlite3_temp_directory variable for the next run of tests:
sqlite3 dbX :memory:
dbX eval {PRAGMA temp_store_directory = ""}
dbX close


ifcapable lock_proxy_pragmas&&prefer_proxy_locking {




  set sqlite_hostid_num 1

  set using_proxy 0
  foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
    set using_proxy $value
  }

  # Test the lock_proxy_file pragmas.
  #
  db close
  set env(SQLITE_FORCE_PROXY_LOCKING) "0"

  sqlite3 db test.db


  do_test pragma-16.1 {
    execsql {
      PRAGMA lock_proxy_file="mylittleproxy";
      select * from sqlite_master;
    }
    execsql {
      PRAGMA lock_proxy_file;

    } 
  } {mylittleproxy}

  do_test pragma-16.2 {
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file="mylittleproxy";
    } db2
  } {}

  db2 close

  do_test pragma-16.2.1 {
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file=":auto:";
      select * from sqlite_master;
    } db2
    execsql {
      PRAGMA lock_proxy_file;
    } db2
  } {mylittleproxy}

  db2 close
  do_test pragma-16.3 {
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file="myotherproxy";
    } db2
    catchsql {
      select * from sqlite_master;
    } db2
  } {1 {database is locked}}




  do_test pragma-16.4 {
    db2 close
    db close
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file="myoriginalproxy";
      PRAGMA lock_proxy_file="myotherproxy";
      PRAGMA lock_proxy_file;
    } db2
  } {myotherproxy}


  db2 close
  set env(SQLITE_FORCE_PROXY_LOCKING) "1"

  do_test pragma-16.5 {
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db2
  } {myotherproxy}
  

  do_test pragma-16.6 {
    db2 close
    sqlite3 db2 test2.db
    set lockpath [execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db2]
    string match "*test2.db:auto:" $lockpath
  } {1}
  
  set sqlite_hostid_num 2

  do_test pragma-16.7 {
    list [catch {
      sqlite3 db test2.db
      execsql { 
        PRAGMA lock_proxy_file=":auto:";
        select * from sqlite_master;
      }
    } msg] $msg
  } {1 {database is locked}}
  db close
  

  do_test pragma-16.8 {
    list [catch {
      sqlite3 db test2.db
      execsql { select * from sqlite_master } 
    } msg] $msg
  } {1 {database is locked}}

  db2 close



  do_test pragma-16.8.1 {
    execsql {
      PRAGMA lock_proxy_file="yetanotherproxy";

      PRAGMA lock_proxy_file;

    } 
  } {yetanotherproxy}
  do_test pragma-16.8.2 {
    execsql {
      create table mine(x);

    } 
  } {}

  db close


  do_test pragma-16.9 {
    sqlite3 db proxytest.db
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath2
  } {1}





























































































  set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
  set sqlite_hostid_num 0
}

# Parsing of auto_vacuum settings.
#







>
|
>
>
>
>













>
>

<
|
|
<
<
|
>
|
|
<


<
|
<



>






|
|
|
|
|
|
|
|
|
|
<





>
>
>




<
|
|
|
<
<
>



>






|

>











>











>








>
>
>

<
|
>
|
>
|
<


|
>




>
>








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







1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554

1555
1556


1557
1558
1559
1560

1561
1562

1563

1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583

1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595

1596
1597
1598


1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648

1649
1650
1651
1652
1653

1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
}

# Reset the sqlite3_temp_directory variable for the next run of tests:
sqlite3 dbX :memory:
dbX eval {PRAGMA temp_store_directory = ""}
dbX close

set skip_lock_proxy_tests [path_is_dos "."]
ifcapable !(lock_proxy_pragmas&&prefer_proxy_locking) {
  set skip_lock_proxy_tests 1
}

if !$skip_lock_proxy_tests {
  set sqlite_hostid_num 1

  set using_proxy 0
  foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
    set using_proxy $value
  }

  # Test the lock_proxy_file pragmas.
  #
  db close
  set env(SQLITE_FORCE_PROXY_LOCKING) "0"

  sqlite3 db test.db
  # set lock proxy name and then query it via pragma interface
  set lpp [exec mktemp -t "proxy1"]
  do_test pragma-16.1 {

    execsql "PRAGMA lock_proxy_file='$lpp'"
    execsql "select * from sqlite_master"


    execsql "PRAGMA lock_proxy_file"
  } $lpp

  # 2 database connections can share a lock proxy file

  do_test pragma-16.2 {
    sqlite3 db2 test.db

    execsql "PRAGMA lock_proxy_file='$lpp'" db2

  } {}

  db2 close
  # 2nd database connection should auto-name an existing lock proxy file
  do_test pragma-16.2.1 {
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file=":auto:";
      select * from sqlite_master;
    } db2
    execsql "PRAGMA lock_proxy_file" db2
  } $lpp

  db2 close
  set lpp2 [exec mktemp -t "proxy2"]

  # 2nd database connection cannot override the lock proxy file
  do_test pragma-16.3 {
    sqlite3 db2 test.db
    execsql "PRAGMA lock_proxy_file='$lpp2'" db2

    catchsql {
      select * from sqlite_master;
    } db2
  } {1 {database is locked}}

  set lpp3 [exec mktemp -t "proxy3"]

  # lock proxy file can be renamed if no other connections are active
  do_test pragma-16.4 {
    db2 close
    db close
    sqlite3 db2 test.db

    execsql "PRAGMA lock_proxy_file='$lpp3'" db2
    execsql "PRAGMA lock_proxy_file='$lpp2'" db2
    execsql "PRAGMA lock_proxy_file" db2


  } $lpp2

  db2 close
  set env(SQLITE_FORCE_PROXY_LOCKING) "1"
  # auto-naming should reuse the last proxy name when available
  do_test pragma-16.5 {
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db2
  } $lpp2
  
  # auto-naming a new proxy should use a predictable & unique name
  do_test pragma-16.6 {
    db2 close
    sqlite3 db2 test2.db
    set lockpath [execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db2]
    string match "*test2.db:auto:" $lockpath
  } {1}
  
  set sqlite_hostid_num 2
  # db access should be limited to one host at a time (simulate 2nd host id)
  do_test pragma-16.7 {
    list [catch {
      sqlite3 db test2.db
      execsql { 
        PRAGMA lock_proxy_file=":auto:";
        select * from sqlite_master;
      }
    } msg] $msg
  } {1 {database is locked}}
  db close
  
  # default to using proxy locking (simulate network file system detection)
  do_test pragma-16.8 {
    list [catch {
      sqlite3 db test2.db
      execsql { select * from sqlite_master } 
    } msg] $msg
  } {1 {database is locked}}

  db2 close
  set lpp4 [exec mktemp -t "proxy4"]

  # check that db is unlocked after first host connection closes 
  do_test pragma-16.8.1 {

    execsql "PRAGMA lock_proxy_file='$lpp4'" 
    execsql "select * from sqlite_master"
    execsql "PRAGMA lock_proxy_file"
  } $lpp4
  

  do_test pragma-16.8.2 {
    execsql {
      create table if not exists mine(x);
      insert into mine values (1);
    } 
  } {}

  db close
  file delete -force proxytest.db
  file delete -force .proxytest.db-conch
  do_test pragma-16.9 {
    sqlite3 db proxytest.db
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath2
  } {1}

  # ensure creating directories for a lock proxy file works
  set lpp5d [exec mktemp -d -t "proxy5"]
  set lpp5 $lpp5d/sub/dir/lock
  db close
  do_test pragma-16.10.1 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp5'" 
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file;
    } db]
    string match "*sub/dir/lock" $lockpath2
  } {1}

  # ensure that after deleting the path, setting ":auto:" works correctly
  db close
  file delete -force $lpp5d
  do_test pragma-16.10.2 {
    sqlite3 db proxytest.db
    set lockpath3 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists pt(y);
      PRAGMA lock_proxy_file;
    } db]
    string match "*sub/dir/lock" $lockpath3
  } {1}

  # ensure that if the path can not be created (file instead of dir)
  # setting :auto: deals with it by creating a new autonamed lock file
  db close
  file delete -force $lpp5d
  close [open "$lpp5d" a]
  do_test pragma-16.10.3 {
    sqlite3 db proxytest.db
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists zz(y);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath2
  } {1}

  # make sure we can deal with ugly file paths correctly
  db close
  file delete -force $lpp5d
  set lpp6 [exec mktemp -d -t "proxy6"]/./././////./proxytest/../proxytest/sub/dir/lock
  do_test pragma-16.10.4 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp6'" 
    set lockpath4 [execsql {
      create table if not exists aa(bb);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest/sub/dir/lock" $lockpath4
  } {1}

  # ensure that if the path can not be created (perm), setting :auto: deals
  db close
  file delete -force $lpp5d
  do_test pragma-16.10.5 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp5'" 
    execsql {
      create table if not exists bb(bb);
    }
    db close
    file delete -force $lpp5d
    file mkdir $lpp5d
    file attributes $lpp5d -permission 0000
    sqlite3 db proxytest.db
    set lockpath5 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists cc(bb);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath5
  } {1}

  # ensure that if the path can not be created, locking fails
  db close
  do_test pragma-16.10.6 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp5'" 
    catchsql {
      create table if not exists faily(y);
      PRAGMA lock_proxy_file;
    } db
  } {1 {database is locked}}
  db close

  file attributes $lpp5d -permission 0777
  file delete -force $lpp5d

  set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
  set sqlite_hostid_num 0
}

# Parsing of auto_vacuum settings.
#

Changes to test/pragma4.test.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
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
  set ::stmt 0
  set ::stmt [sqlite3_prepare_v2 db $sql -1 dummy]
  uplevel [list do_test $tn { sqlite3_column_count $::stmt } $nCol]
  sqlite3_finalize $::stmt
}

# If there is no RHS argument, the following PRAGMA statements operate as
# queries, returning a single row containing a single column.
#
# Or, if there is RHS argument, they return zero rows of zero columns.
#
foreach {tn sql} {
  1 "PRAGMA application_id = 10"
  2 "PRAGMA automatic_index = 1"
  3 "PRAGMA auto_vacuum = 1"
................................................................................
 20 "PRAGMA query_only = false"
 21 "PRAGMA read_uncommitted = true"
 22 "PRAGMA recursive_triggers = false"
 23 "PRAGMA reverse_unordered_selects = false"
 24 "PRAGMA schema_version = 211"
 25 "PRAGMA short_column_names = 1"
 26 "PRAGMA synchronous = full"


 29 "PRAGMA temp_store = memory"
 30 "PRAGMA user_version = 405"
 31 "PRAGMA writable_schema = 1"
} {
  reset_db

  # Without RHS:
  do_pragma_ncol_test 1.$tn.1 [lindex [split $sql =] 0] 1

  # With RHS:
  do_pragma_ncol_test 1.$tn.2 $sql  0
}

# These pragmas should never return any values.
#
foreach {tn sql} {
................................................................................
  1 "PRAGMA shrink_memory"
  2 "PRAGMA shrink_memory = 10"
  3 "PRAGMA case_sensitive_like = 0"
  4 "PRAGMA case_sensitive_like = 1"
  5 "PRAGMA case_sensitive_like"
} {

  do_pragma_ncol_test 1.$tn.1 $sql 0
}

# EXPLAIN on a PRAGMA integrity_check.
# Verify that that P4_INTARRAY argument to OP_IntegrityCk is rendered
# correctly.
#
db close







|







 







>
>








|







 







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
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
  set ::stmt 0
  set ::stmt [sqlite3_prepare_v2 db $sql -1 dummy]
  uplevel [list do_test $tn { sqlite3_column_count $::stmt } $nCol]
  sqlite3_finalize $::stmt
}

# If there is no RHS argument, the following PRAGMA statements operate as
# queries, returning a single row containing a single column. 
#
# Or, if there is RHS argument, they return zero rows of zero columns.
#
foreach {tn sql} {
  1 "PRAGMA application_id = 10"
  2 "PRAGMA automatic_index = 1"
  3 "PRAGMA auto_vacuum = 1"
................................................................................
 20 "PRAGMA query_only = false"
 21 "PRAGMA read_uncommitted = true"
 22 "PRAGMA recursive_triggers = false"
 23 "PRAGMA reverse_unordered_selects = false"
 24 "PRAGMA schema_version = 211"
 25 "PRAGMA short_column_names = 1"
 26 "PRAGMA synchronous = full"
 27 "PRAGMA temp_store_directory = '/tmp'"
 28 "PRAGMA temp_store_directory = ''"
 29 "PRAGMA temp_store = memory"
 30 "PRAGMA user_version = 405"
 31 "PRAGMA writable_schema = 1"
} {
  reset_db

  # Without RHS:
  do_pragma_ncol_test 1.$tn.1 [lindex [split $sql =] 0] 1
   
  # With RHS:
  do_pragma_ncol_test 1.$tn.2 $sql  0
}

# These pragmas should never return any values.
#
foreach {tn sql} {
................................................................................
  1 "PRAGMA shrink_memory"
  2 "PRAGMA shrink_memory = 10"
  3 "PRAGMA case_sensitive_like = 0"
  4 "PRAGMA case_sensitive_like = 1"
  5 "PRAGMA case_sensitive_like"
} {

  do_pragma_ncol_test 2.$tn.1 $sql 0
}

# EXPLAIN on a PRAGMA integrity_check.
# Verify that that P4_INTARRAY argument to OP_IntegrityCk is rendered
# correctly.
#
db close

Changes to test/rowallock.test.

7
8
9
10
11
12
13




14
15
16
17
18


19
20
21
22
23
24
25
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing locks on read-only WAL-mode databases.





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



set mmap_res 1000000
ifcapable !mmap {
  set mmap_res 0
}

do_multiclient_test tn {







>
>
>
>





>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing locks on read-only WAL-mode databases.
#
# Note that the apple-osx branch does not allow read-only WAL-mode
# databases (per check-in from Adam Swift on 2011-06-24 20:47:06) and
# so this test module is disabled in the apple-osx branch.

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

finish_test; return ;# This test module disabled in the apple-osx branch

set mmap_res 1000000
ifcapable !mmap {
  set mmap_res 0
}

do_multiclient_test tn {

Changes to test/shared.test.

41
42
43
44
45
46
47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
    break
  }
}

# if we're using proxy locks, we use 2 filedescriptors for a db
# that is open but NOT yet locked, after a lock is taken we'll have 3, 
# normally sqlite uses 1 (proxy locking adds the conch and the local lock)
set using_proxy 0
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
  set using_proxy $value
}
set extrafds_prelock 0
set extrafds_postlock 0
if {$using_proxy>0} {

  set extrafds_prelock 1
  set extrafds_postlock 2
} 

# $av is currently 0 if this loop iteration is to test with auto-vacuum turned
# off, and 1 if it is turned on. Increment it so that (1 -> no auto-vacuum) 
# and (2 -> auto-vacuum). The sole reason for this is so that it looks nicer







<
<
<
<


<
>







41
42
43
44
45
46
47




48
49

50
51
52
53
54
55
56
57
    break
  }
}

# if we're using proxy locks, we use 2 filedescriptors for a db
# that is open but NOT yet locked, after a lock is taken we'll have 3, 
# normally sqlite uses 1 (proxy locking adds the conch and the local lock)




set extrafds_prelock 0
set extrafds_postlock 0

if {[forced_proxy_locking]} {
  set extrafds_prelock 1
  set extrafds_postlock 2
} 

# $av is currently 0 if this loop iteration is to test with auto-vacuum turned
# off, and 1 if it is turned on. Increment it so that (1 -> no auto-vacuum) 
# and (2 -> auto-vacuum). The sole reason for this is so that it looks nicer

Changes to test/shrink.test.

13
14
15
16
17
18
19





20
21
22
23
24
25
26
# the PRAGMA shrink_memory statement.
#

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






unset -nocomplain baseline
do_test shrink-1.1 {
  db eval {
    PRAGMA cache_size = 2000;
    CREATE TABLE t1(x,y);
    INSERT INTO t1 VALUES(randomblob(1000000),1);
  }







>
>
>
>
>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# the PRAGMA shrink_memory statement.
#

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

# purgeable pcache tracks memory differently
ifcapable {enable_purgeable_pcache} {
  finish_test
  return
}
unset -nocomplain baseline
do_test shrink-1.1 {
  db eval {
    PRAGMA cache_size = 2000;
    CREATE TABLE t1(x,y);
    INSERT INTO t1 VALUES(randomblob(1000000),1);
  }

Changes to test/stmt.test.

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
#
# This only work if SQLITE_TEMP_STORE!=3
#
if {$::TEMP_STORE==3} {
  finish_test
  return
}










do_test stmt-1.2 {
  set sqlite_open_file_count

} {1}
do_test stmt-1.3 {
  execsql {
    PRAGMA temp_store = file;
    BEGIN;
      INSERT INTO t1 VALUES(1, 1);
  }
  set sqlite_open_file_count

} {2}
do_test stmt-1.4 {
  execsql {
    INSERT INTO t1 SELECT a+1, b+1 FROM t1;
  }
  set sqlite_open_file_count

  # 2016-03-04: statement-journal open deferred
} {2}
do_test stmt-1.5 {
  execsql COMMIT
  set sqlite_open_file_count

} {1}
do_test stmt-1.6.1 {
  execsql {
    BEGIN;
      INSERT INTO t1 SELECT a+2, b+2 FROM t1;
  }
  set sqlite_open_file_count

} {2}
do_test stmt-1.6.2 {
  execsql { INSERT INTO t1 SELECT a+4, b+4 FROM t1 }
  set sqlite_open_file_count

  # 2016-03-04: statement-journal open deferred
} {2}
do_test stmt-1.7 {
  execsql COMMIT
  set sqlite_open_file_count

} {1}


proc filecount {testname sql expected} {
  uplevel [list do_test $testname [subst -nocommand {
    execsql BEGIN
    execsql { $sql }
    set ret [set sqlite_open_file_count]
    execsql ROLLBACK
    set ret
  }] $expected]
}

filecount stmt-2.1 { INSERT INTO t1 VALUES(9, 9)  } 2
filecount stmt-2.2 { REPLACE INTO t1 VALUES(9, 9) } 2
filecount stmt-2.3 { INSERT INTO t1 SELECT 9, 9   } 2
filecount stmt-2.4 { 
    INSERT INTO t1 SELECT 9, 9;
    INSERT INTO t1 SELECT 10, 10;
} 2

do_test stmt-2.5 {
  execsql { CREATE INDEX i1 ON t1(b) }
} {}
filecount stmt-2.6 { 
  REPLACE INTO t1 VALUES(5, 5);
  REPLACE INTO t1 VALUES(5, 5); 
} 2

finish_test







>
>
>
>
>
>
>
>
>
>


>








>






>





>







>




>





>



|






|


|
|
|



|







|


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
#
# This only work if SQLITE_TEMP_STORE!=3
#
if {$::TEMP_STORE==3} {
  finish_test
  return
}

# if we're using proxy locks, we use 3 filedescriptors for a db
# that is open but NOT writing changes, normally
# sqlite uses 1 (proxy locking adds the conch and the local lock)
set extrafds 0
if {[forced_proxy_locking]} {
  set extrafds 2
} 


do_test stmt-1.2 {
  set sqlite_open_file_count
  expr $sqlite_open_file_count-$extrafds
} {1}
do_test stmt-1.3 {
  execsql {
    PRAGMA temp_store = file;
    BEGIN;
      INSERT INTO t1 VALUES(1, 1);
  }
  set sqlite_open_file_count
  expr $sqlite_open_file_count-$extrafds
} {2}
do_test stmt-1.4 {
  execsql {
    INSERT INTO t1 SELECT a+1, b+1 FROM t1;
  }
  set sqlite_open_file_count
  expr $sqlite_open_file_count-$extrafds
  # 2016-03-04: statement-journal open deferred
} {2}
do_test stmt-1.5 {
  execsql COMMIT
  set sqlite_open_file_count
  expr $sqlite_open_file_count-$extrafds
} {1}
do_test stmt-1.6.1 {
  execsql {
    BEGIN;
      INSERT INTO t1 SELECT a+2, b+2 FROM t1;
  }
  set sqlite_open_file_count
  expr $sqlite_open_file_count-$extrafds
} {2}
do_test stmt-1.6.2 {
  execsql { INSERT INTO t1 SELECT a+4, b+4 FROM t1 }
  set sqlite_open_file_count
  expr $sqlite_open_file_count-$extrafds
  # 2016-03-04: statement-journal open deferred
} {2}
do_test stmt-1.7 {
  execsql COMMIT
  set sqlite_open_file_count
  expr $sqlite_open_file_count-$extrafds
} {1}


proc filecount {testname sql expected extrafds} {
  uplevel [list do_test $testname [subst -nocommand {
    execsql BEGIN
    execsql { $sql }
    set ret [set sqlite_open_file_count]
    execsql ROLLBACK
    set ret
  }] [ expr $expected+$extrafds ] ]
}

filecount stmt-2.1 { INSERT INTO t1 VALUES(9, 9)  } 2 $extrafds
filecount stmt-2.2 { REPLACE INTO t1 VALUES(9, 9) } 2 $extrafds
filecount stmt-2.3 { INSERT INTO t1 SELECT 9, 9   } 2 $extrafds
filecount stmt-2.4 { 
    INSERT INTO t1 SELECT 9, 9;
    INSERT INTO t1 SELECT 10, 10;
} 2 $extrafds

do_test stmt-2.5 {
  execsql { CREATE INDEX i1 ON t1(b) }
} {}
filecount stmt-2.6 { 
  REPLACE INTO t1 VALUES(5, 5);
  REPLACE INTO t1 VALUES(5, 5); 
} 2 $extrafds

finish_test

Changes to test/superlock.test.

9
10
11
12
13
14
15

16
17
18
19
20
21
22
..
38
39
40
41
42
43
44





45
46
47
48
49
50
51
..
53
54
55
56
57
58
59






60
61
62
63
64
65
66
#
#***********************************************************************
#

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


set testprefix superlock
do_not_use_codec

# Test organization:
#
#   1.*: Test superlock on a rollback database. Test that once the db is
................................................................................
#        handler returns 0 before said clients relinquish their locks.
#
#   6.*: Test that if a superlocked WAL database is overwritten, existing
#        clients run the recovery to build the new wal-index after the 
#        superlock is released.
#        
#






do_execsql_test 1.1 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  PRAGMA journal_mode = DELETE;
} {delete}

................................................................................
  finish_test
  return
}

do_test 1.2 { sqlite3demo_superlock unlock test.db } {unlock}
do_catchsql_test 1.3 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.4 { unlock } {}







do_execsql_test 2.1 { 
  INSERT INTO t1 VALUES(3, 4);
  PRAGMA journal_mode = WAL;
} {wal}

do_test 2.2 { sqlite3demo_superlock unlock test.db } {unlock}







>







 







>
>
>
>
>







 







>
>
>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
..
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#
#***********************************************************************
#

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

set testprefix superlock
do_not_use_codec

# Test organization:
#
#   1.*: Test superlock on a rollback database. Test that once the db is
................................................................................
#        handler returns 0 before said clients relinquish their locks.
#
#   6.*: Test that if a superlocked WAL database is overwritten, existing
#        clients run the recovery to build the new wal-index after the 
#        superlock is released.
#        
#

if {[forced_proxy_locking]} {
  finish_test 
  return 
}

do_execsql_test 1.1 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  PRAGMA journal_mode = DELETE;
} {delete}

................................................................................
  finish_test
  return
}

do_test 1.2 { sqlite3demo_superlock unlock test.db } {unlock}
do_catchsql_test 1.3 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.4 { unlock } {}

ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] } {
  finish_test 
  return 
}

do_execsql_test 2.1 { 
  INSERT INTO t1 VALUES(3, 4);
  PRAGMA journal_mode = WAL;
} {wal}

do_test 2.2 { sqlite3demo_superlock unlock test.db } {unlock}

Changes to test/tempdb.test.

52
53
54
55
56
57
58





59
60
61
62
63
64
65
..
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Verify that no writes occurred in t1.
#
do_test tempdb-1.2 {
  execsql {
    SELECT * FROM t1
  }
} {}






do_test tempdb-2.1 {
  # Set $::jrnl_in_memory if the journal file is expected to be in-memory.
  # Similarly, set $::subj_in_memory if the sub-journal file is expected
  # to be in memory. These variables are used to calculate the expected
  # number of open files in the test cases below.
  #
................................................................................
      INSERT INTO t1 VALUES(1, 2, 3);
      INSERT INTO t1 VALUES(4, 5, 6);
      INSERT INTO t2 VALUES(7, 8, 9);
      INSERT INTO t2 SELECT * FROM t1;
  }
  catchsql { INSERT INTO t1 SELECT * FROM t2 }
  set sqlite_open_file_count
} [expr 1 + (0==$jrnl_in_memory)]
do_test tempdb-2.3 {
  execsql {
    PRAGMA temp_store = 'memory';
    ROLLBACK;
    BEGIN;
      INSERT INTO t1 VALUES(1, 2, 3);
      INSERT INTO t1 VALUES(4, 5, 6);
      INSERT INTO t2 SELECT * FROM t1;
  }
  catchsql { INSERT INTO t1 SELECT * FROM t2 }
  set sqlite_open_file_count
} [expr 1 + (0==$jrnl_in_memory)]

finish_test







>
>
>
>
>







 







|











|


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Verify that no writes occurred in t1.
#
do_test tempdb-1.2 {
  execsql {
    SELECT * FROM t1
  }
} {}

set extrafds 0
if {[forced_proxy_locking]} {
  set extrafds 2
}

do_test tempdb-2.1 {
  # Set $::jrnl_in_memory if the journal file is expected to be in-memory.
  # Similarly, set $::subj_in_memory if the sub-journal file is expected
  # to be in memory. These variables are used to calculate the expected
  # number of open files in the test cases below.
  #
................................................................................
      INSERT INTO t1 VALUES(1, 2, 3);
      INSERT INTO t1 VALUES(4, 5, 6);
      INSERT INTO t2 VALUES(7, 8, 9);
      INSERT INTO t2 SELECT * FROM t1;
  }
  catchsql { INSERT INTO t1 SELECT * FROM t2 }
  set sqlite_open_file_count
} [expr 1 + $extrafds + (0==$jrnl_in_memory)]
do_test tempdb-2.3 {
  execsql {
    PRAGMA temp_store = 'memory';
    ROLLBACK;
    BEGIN;
      INSERT INTO t1 VALUES(1, 2, 3);
      INSERT INTO t1 VALUES(4, 5, 6);
      INSERT INTO t2 SELECT * FROM t1;
  }
  catchsql { INSERT INTO t1 SELECT * FROM t2 }
  set sqlite_open_file_count
} [expr 1 + $extrafds + (0==$jrnl_in_memory)]

finish_test

Changes to test/tester.tcl.

590
591
592
593
594
595
596

















597
598
599
600
601
602
603
604








605
606
607
608
609
610
611
....
1307
1308
1309
1310
1311
1312
1313

1314
1315
1316


1317
1318

1319
1320
1321
1322
1323
1324
1325
....
2222
2223
2224
2225
2226
2227
2228













2229
2230
2231
2232
2233
2234
2235

# Update the soft-heap-limit each time this script is run. In that
# way if an individual test file changes the soft-heap-limit, it
# will be reset at the start of the next test file.
#
sqlite3_soft_heap_limit64 $cmdlinearg(soft-heap-limit)
sqlite3_hard_heap_limit64 $cmdlinearg(hard-heap-limit)


















# Create a test database
#
proc reset_db {} {
  catch {db close}
  forcedelete test.db
  forcedelete test.db-journal
  forcedelete test.db-wal








  sqlite3 db ./test.db
  set ::DB [sqlite3_connection_pointer db]
  if {[info exists ::SETUP_SQL]} {
    db eval $::SETUP_SQL
  }
}
reset_db
................................................................................
      sqlite3_memdebug_log sync
      memdebug_log_sql leaks.tcl
    }
  }
  if {[info commands vdbe_coverage]!=""} {
    vdbe_coverage_report
  }

  foreach f [glob -nocomplain test.db-*-journal] {
    forcedelete $f
  }


  foreach f [glob -nocomplain test.db-mj*] {
    forcedelete $f

  }
  exit [expr {$nErr>0}]
}

proc vdbe_coverage_report {} {
  puts "Writing vdbe coverage report to vdbe_coverage.txt"
  set lSrc [list]
................................................................................
  set perm
}
proc presql {} {
  set presql ""
  catch {set presql $::G(perm:presql)}
  set presql
}














proc isquick {} {
  set ret 0
  catch {set ret $::G(isquick)}
  set ret
}








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








>
>
>
>
>
>
>
>







 







>
|
|
|
>
>
|
|
>







 







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







590
591
592
593
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
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
....
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
....
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

# Update the soft-heap-limit each time this script is run. In that
# way if an individual test file changes the soft-heap-limit, it
# will be reset at the start of the next test file.
#
sqlite3_soft_heap_limit64 $cmdlinearg(soft-heap-limit)
sqlite3_hard_heap_limit64 $cmdlinearg(hard-heap-limit)

proc forced_proxy_locking {} {
  if $::sqlite_options(lock_proxy_pragmas)&&$::sqlite_options(prefer_proxy_locking) {
    set force_proxy_value 0
    set force_key "SQLITE_FORCE_PROXY_LOCKING="
    foreach {env_pair} [exec env] { 
      if { [string first $force_key $env_pair] == 0} {
        set force_proxy_value [string range $env_pair [string length $force_key] end]
      }
    }
    if { "$force_proxy_value " == "1 " } {
      return 1
    } 
  }
  return 0
}


# Create a test database
#
proc reset_db {} {
  catch {db close}
  forcedelete test.db
  forcedelete test.db-journal
  forcedelete test.db-wal
  if {[forced_proxy_locking]} {
    sqlite3 db ./test.db
    set lock_proxy_path [db eval "PRAGMA lock_proxy_file;"] 
    catch {db close}
    # puts "deleting $lock_proxy_path"
    file delete -force $lock_proxy_path    
    file delete -force test.db
  }
  sqlite3 db ./test.db
  set ::DB [sqlite3_connection_pointer db]
  if {[info exists ::SETUP_SQL]} {
    db eval $::SETUP_SQL
  }
}
reset_db
................................................................................
      sqlite3_memdebug_log sync
      memdebug_log_sql leaks.tcl
    }
  }
  if {[info commands vdbe_coverage]!=""} {
    vdbe_coverage_report
  }
  catch {
    foreach f [glob -nocomplain test.db-*-journal] {
      forcedelete $f
    }
  }
  catch {
    foreach f [glob -nocomplain test.db-mj*] {
      forcedelete $f
    }
  }
  exit [expr {$nErr>0}]
}

proc vdbe_coverage_report {} {
  puts "Writing vdbe coverage report to vdbe_coverage.txt"
  set lSrc [list]
................................................................................
  set perm
}
proc presql {} {
  set presql ""
  catch {set presql $::G(perm:presql)}
  set presql
}

proc wal_is_ok {} {
  if { [forced_proxy_locking] } {
    return 1
  }
  if { ![path_is_local "."] } {
    return 0
  }
  if { [path_is_dos "."] } {
    return 0
  }
  return 1
}

proc isquick {} {
  set ret 0
  catch {set ret $::G(isquick)}
  set ret
}

Changes to test/tkt-2d1a5c67d.test.

17
18
19
20
21
22
23

24
25
26
27
28
29
30

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-2d1a5c67d

ifcapable {!vtab} {finish_test; return}
if {[wal_is_capable]==0} {finish_test; return}


for {set ii 1} {$ii<=10} {incr ii} {
  do_test tkt-2d1a5c67d.1.$ii {
    db close
    forcedelete test.db test.db-wal
    sqlite3 db test.db
    db eval "PRAGMA cache_size=$::ii"







>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-2d1a5c67d

ifcapable {!vtab} {finish_test; return}
if {[wal_is_capable]==0} {finish_test; return}
if {![wal_is_ok]} {finish_test; return}

for {set ii 1} {$ii<=10} {incr ii} {
  do_test tkt-2d1a5c67d.1.$ii {
    db close
    forcedelete test.db test.db-wal
    sqlite3 db test.db
    db eval "PRAGMA cache_size=$::ii"

Changes to test/tkt-313723c356.test.

15
16
17
18
19
20
21

22
23
24
25
26
27
28
#

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

if {![wal_is_capable]} { finish_test ; return }


do_execsql_test tkt-313723c356.1 {
  PRAGMA page_size = 1024;
  PRAGMA journal_mode = WAL;
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a, b);
  INSERT INTO t1 VALUES(randomblob(400), randomblob(400));







>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#

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

if {![wal_is_capable]} { finish_test ; return }
if ![wal_is_ok] { finish_test; return }

do_execsql_test tkt-313723c356.1 {
  PRAGMA page_size = 1024;
  PRAGMA journal_mode = WAL;
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a, b);
  INSERT INTO t1 VALUES(randomblob(400), randomblob(400));

Changes to test/tkt3457.test.

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
# permission bits on us
#
catch {
  test_syscall install fchmod
  test_syscall fault 1 1
}


do_test tkt3457-1.2 {
  forcecopy bak.db-journal test.db-journal
  file attributes test.db-journal -permissions ---------
  catchsql { SELECT * FROM t1 }
} {1 {unable to open database file}}
do_test tkt3457-1.3 {
  forcecopy bak.db-journal test.db-journal
  file attributes test.db-journal -permissions -w--w--w-
  catchsql { SELECT * FROM t1 }
} {1 {unable to open database file}}
do_test tkt3457-1.4 {
  forcecopy bak.db-journal test.db-journal
  file attributes test.db-journal -permissions r--r--r--
  catchsql { SELECT * FROM t1 }
} {1 {unable to open database file}}

do_test tkt3457-1.5 {
  forcecopy bak.db-journal test.db-journal
  file attributes test.db-journal -permissions rw-rw-rw-
  catchsql { SELECT * FROM t1 }
} {0 {1 2 3 4 5 6}}


# Reenable fchmod
catch {
  test_syscall uninstall
  test_syscall fault 0 0
}

finish_test







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








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
# permission bits on us
#
catch {
  test_syscall install fchmod
  test_syscall fault 1 1
}

if { ![path_is_dos "."] } {
  do_test tkt3457-1.2 {
    forcecopy bak.db-journal test.db-journal
    file attributes test.db-journal -permissions ---------
    catchsql { SELECT * FROM t1 }
  } {1 {unable to open database file}}
  do_test tkt3457-1.3 {
    forcecopy bak.db-journal test.db-journal
    file attributes test.db-journal -permissions -w--w--w-
    catchsql { SELECT * FROM t1 }
  } {1 {unable to open database file}}
  do_test tkt3457-1.4 {
    forcecopy bak.db-journal test.db-journal
    file attributes test.db-journal -permissions r--r--r--
    catchsql { SELECT * FROM t1 }
  } {1 {unable to open database file}}

  do_test tkt3457-1.5 {
    forcecopy bak.db-journal test.db-journal
    file attributes test.db-journal -permissions rw-rw-rw-
    catchsql { SELECT * FROM t1 }
  } {0 {1 2 3 4 5 6}}
}

# Reenable fchmod
catch {
  test_syscall uninstall
  test_syscall fault 0 0
}

finish_test

Changes to test/wal.test.

18
19
20
21
22
23
24




25
26
27
28
29
30
31
...
169
170
171
172
173
174
175



176
177
178
179
180
181
182
...
220
221
222
223
224
225
226



227
228
229
230
231
232
233
...
334
335
336
337
338
339
340



341
342
343
344
345
346
347
...
720
721
722
723
724
725
726



727
728
729
730
731
732
733
...
734
735
736
737
738
739
740



741
742
743
744
745
746
747
...
781
782
783
784
785
786
787



788
789
790
791
792
793
794
...
818
819
820
821
822
823
824



825
826
827
828
829
830
831
...
975
976
977
978
979
980
981

982
983

984
985
986
987
988
989
990
991
992
....
1049
1050
1051
1052
1053
1054
1055

1056
1057
1058
1059
1060
1061
1062
....
1264
1265
1266
1267
1268
1269
1270



1271
1272
1273
1274
1275
1276
1277
....
1418
1419
1420
1421
1422
1423
1424



1425
1426
1427
1428
1429
1430
1431
....
1464
1465
1466
1467
1468
1469
1470



1471
1472
1473
1474
1475
1476
1477
....
1492
1493
1494
1495
1496
1497
1498



1499
1500
1501
1502
1503
1504
1505
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

set testprefix wal

ifcapable !wal {finish_test ; return }




test_set_config_pagecache 0 0

proc reopen_db {} {
  catch { db close }
  forcedelete test.db test.db-wal test.db-wal-summary
  sqlite3_wal db test.db
}
................................................................................
  execsql {
    COMMIT;
    SELECT * FROM t1;
  }
} {a b}

do_test wal-4.4.1 {



  db close
  sqlite3 db test.db
  db func blob blob
  list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
} {{a b} 0}
do_test wal-4.4.2 {
  execsql { PRAGMA cache_size = 10 }
................................................................................
do_test wal-4.4.7 {
  execsql { PRAGMA integrity_check } db2
} {ok}
db2 close

do_test wal-4.5.1 {
  reopen_db



  db func blob blob
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES('a', 'b');
  }
  sqlite3 db test.db
................................................................................

foreach sector {512 4096} {
  sqlite3_simulate_device -sectorsize $sector
  foreach pgsz {512 1024 2048 4096} {
    forcedelete test.db test.db-wal
    do_test wal-6.$sector.$pgsz.1 {
      sqlite3 db test.db -vfs devsym



      execsql "
        PRAGMA page_size = $pgsz;
        PRAGMA auto_vacuum = 0;
        PRAGMA journal_mode = wal;
      "
      execsql "
        CREATE TABLE t1(a, b);
................................................................................
  }
} {16 ok}
do_test wal-11.8 {
  execsql { PRAGMA wal_checkpoint }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 40 1024]]
do_test wal-11.9 {



  db close
  list [expr [file size test.db]/1024] [log_deleted test.db-wal]
} {37 1}
sqlite3_wal db test.db

# After adding the capability of WAL to overwrite prior uncommitted
# frame in the WAL-file with revised content, the size of the WAL file
................................................................................
# following cache-spill is smaller.
#
#set nWal 39
#if {[permutation]!="mmap"} {set nWal 37}
#ifcapable !mmap {set nWal 37}
set nWal 34




do_test wal-11.10 {
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 32
      SELECT count(*) FROM t1;
  }
................................................................................
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
    INSERT INTO t1 VALUES('A', 1);
  }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 1 [wal_file_size 5 1024]]
do_test wal-12.2 {



  db close
  sqlite3 db test.db
  execsql {
    PRAGMA synchronous = normal;
    UPDATE t1 SET y = 0 WHERE x = 'A';
  }
  list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
................................................................................
do_test wal-12.6 {
  forcecopy test.db test2.db
  forcecopy test.db-wal test2.db-wal
  sqlite3_wal db2 test2.db
  execsql { SELECT * FROM t2 } db2
} {B 2}
db2 close



db close

#-------------------------------------------------------------------------
# Check a fun corruption case has been fixed.
#
# The problem was that after performing a checkpoint using a connection
# that had an out-of-date pager-cache, the next time the connection was
................................................................................
    sqlite3 db test.db
    execsql {
      ATTACH 'test2.db' AS aux;
      PRAGMA main.auto_vacuum = 0;
      PRAGMA aux.auto_vacuum = 0;
      PRAGMA main.journal_mode = WAL;
      PRAGMA aux.journal_mode = WAL;

      PRAGMA main.synchronous = NORMAL;
      PRAGMA aux.synchronous = NORMAL;

    }
  } {wal wal}

  do_test wal-16.$tn.2 {
    execsql {
      CREATE TABLE main.t1(a, b, PRIMARY KEY(a, b));
      CREATE TABLE aux.t2(a, b, PRIMARY KEY(a, b));

      INSERT INTO t2 VALUES(1, randomblob(1000));
................................................................................

  do_test wal-17.$tn.1 {
    execsql {
      PRAGMA auto_vacuum = 0;
      PRAGMA page_size = 512;
      PRAGMA cache_size = -2000;
      PRAGMA journal_mode = WAL;

      PRAGMA synchronous = FULL;
    }
    execsql {
      BEGIN;
      CREATE TABLE t(x);
    }
    for {set i 0} {$i<166} {incr i} {
................................................................................
do_test wal-19.2 {
  execsql {
    INSERT INTO t1 VALUES(5, 6);
    SELECT * FROM t1;
  }
} {1 2 3 4 5 6}
do_test wal-19.3 {



  db close
  db2 close
  file exists test.db-wal
} {0}
do_test wal-19.4 {
  # When the bug was present, the following was returning {1 2 3 4} only,
  # as [db2] had an out-of-date copy of the wal-index header when it was
................................................................................
  faultsim_delete_and_reopen
  execsql {
    CREATE TABLE t1(a, b);
    PRAGMA journal_mode = WAL;
    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
  }



  faultsim_save_and_close

  sqlite3_shutdown
  test_sqlite3_log [list lappend ::log]
  set ::log [list]
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }
................................................................................
    INSERT INTO t1 VALUES(randomblob(5000));
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
  } {wal}
  do_test 24.2 { 



    execsql {
      DELETE FROM t1;
      PRAGMA wal_checkpoint;
    }
    db close
    sqlite3 db test.db
    file exists test.db-wal
................................................................................
  # It would be two frames (the new root page and a padding frame) if the
  # ZERO_DAMAGE flag were not set.
  do_test 24.5 {
    file size test.db-wal
  } [wal_file_size 1 1024]
}




db close
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize

# Make sure PRAGMA journal_mode=WAL works with ATTACHED databases in
# all journal modes.







>
>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>


>

|







 







>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
...
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
...
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
...
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
....
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
....
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
....
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
....
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
....
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
....
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

set testprefix wal

ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] } {
  finish_test 
  return 
}
test_set_config_pagecache 0 0

proc reopen_db {} {
  catch { db close }
  forcedelete test.db test.db-wal test.db-wal-summary
  sqlite3_wal db test.db
}
................................................................................
  execsql {
    COMMIT;
    SELECT * FROM t1;
  }
} {a b}

do_test wal-4.4.1 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  sqlite3 db test.db
  db func blob blob
  list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
} {{a b} 0}
do_test wal-4.4.2 {
  execsql { PRAGMA cache_size = 10 }
................................................................................
do_test wal-4.4.7 {
  execsql { PRAGMA integrity_check } db2
} {ok}
db2 close

do_test wal-4.5.1 {
  reopen_db
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db func blob blob
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES('a', 'b');
  }
  sqlite3 db test.db
................................................................................

foreach sector {512 4096} {
  sqlite3_simulate_device -sectorsize $sector
  foreach pgsz {512 1024 2048 4096} {
    forcedelete test.db test.db-wal
    do_test wal-6.$sector.$pgsz.1 {
      sqlite3 db test.db -vfs devsym
      ifcapable enable_persist_wal {
        file_control_persist_wal db 0
      }
      execsql "
        PRAGMA page_size = $pgsz;
        PRAGMA auto_vacuum = 0;
        PRAGMA journal_mode = wal;
      "
      execsql "
        CREATE TABLE t1(a, b);
................................................................................
  }
} {16 ok}
do_test wal-11.8 {
  execsql { PRAGMA wal_checkpoint }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 40 1024]]
do_test wal-11.9 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  list [expr [file size test.db]/1024] [log_deleted test.db-wal]
} {37 1}
sqlite3_wal db test.db

# After adding the capability of WAL to overwrite prior uncommitted
# frame in the WAL-file with revised content, the size of the WAL file
................................................................................
# following cache-spill is smaller.
#
#set nWal 39
#if {[permutation]!="mmap"} {set nWal 37}
#ifcapable !mmap {set nWal 37}
set nWal 34

ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
do_test wal-11.10 {
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 32
      SELECT count(*) FROM t1;
  }
................................................................................
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
    INSERT INTO t1 VALUES('A', 1);
  }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 1 [wal_file_size 5 1024]]
do_test wal-12.2 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  sqlite3 db test.db
  execsql {
    PRAGMA synchronous = normal;
    UPDATE t1 SET y = 0 WHERE x = 'A';
  }
  list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
................................................................................
do_test wal-12.6 {
  forcecopy test.db test2.db
  forcecopy test.db-wal test2.db-wal
  sqlite3_wal db2 test2.db
  execsql { SELECT * FROM t2 } db2
} {B 2}
db2 close
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close

#-------------------------------------------------------------------------
# Check a fun corruption case has been fixed.
#
# The problem was that after performing a checkpoint using a connection
# that had an out-of-date pager-cache, the next time the connection was
................................................................................
    sqlite3 db test.db
    execsql {
      ATTACH 'test2.db' AS aux;
      PRAGMA main.auto_vacuum = 0;
      PRAGMA aux.auto_vacuum = 0;
      PRAGMA main.journal_mode = WAL;
      PRAGMA aux.journal_mode = WAL;
      SELECT count(*) FROM main.sqlite_master, aux.sqlite_master;
      PRAGMA main.synchronous = NORMAL;
      PRAGMA aux.synchronous = NORMAL;
      PRAGMA aux.synchronous = FULL;
    }
  } {wal wal 0}

  do_test wal-16.$tn.2 {
    execsql {
      CREATE TABLE main.t1(a, b, PRIMARY KEY(a, b));
      CREATE TABLE aux.t2(a, b, PRIMARY KEY(a, b));

      INSERT INTO t2 VALUES(1, randomblob(1000));
................................................................................

  do_test wal-17.$tn.1 {
    execsql {
      PRAGMA auto_vacuum = 0;
      PRAGMA page_size = 512;
      PRAGMA cache_size = -2000;
      PRAGMA journal_mode = WAL;
      SELECT * FROM sqlite_master;
      PRAGMA synchronous = FULL;
    }
    execsql {
      BEGIN;
      CREATE TABLE t(x);
    }
    for {set i 0} {$i<166} {incr i} {
................................................................................
do_test wal-19.2 {
  execsql {
    INSERT INTO t1 VALUES(5, 6);
    SELECT * FROM t1;
  }
} {1 2 3 4 5 6}
do_test wal-19.3 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db2 0
  }
  db close
  db2 close
  file exists test.db-wal
} {0}
do_test wal-19.4 {
  # When the bug was present, the following was returning {1 2 3 4} only,
  # as [db2] had an out-of-date copy of the wal-index header when it was
................................................................................
  faultsim_delete_and_reopen
  execsql {
    CREATE TABLE t1(a, b);
    PRAGMA journal_mode = WAL;
    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
  }
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  faultsim_save_and_close

  sqlite3_shutdown
  test_sqlite3_log [list lappend ::log]
  set ::log [list]
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }
................................................................................
    INSERT INTO t1 VALUES(randomblob(5000));
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
  } {wal}
  do_test 24.2 { 
    ifcapable enable_persist_wal {
      file_control_persist_wal db 0
    }
    execsql {
      DELETE FROM t1;
      PRAGMA wal_checkpoint;
    }
    db close
    sqlite3 db test.db
    file exists test.db-wal
................................................................................
  # It would be two frames (the new root page and a padding frame) if the
  # ZERO_DAMAGE flag were not set.
  do_test 24.5 {
    file size test.db-wal
  } [wal_file_size 1 1024]
}

ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize

# Make sure PRAGMA journal_mode=WAL works with ATTACHED databases in
# all journal modes.

Changes to test/wal2.test.

18
19
20
21
22
23
24

25
26
27
28
29
30
31
..
66
67
68
69
70
71
72







73
74
75
76
77
78
79
...
569
570
571
572
573
574
575



576
577
578



579
580
581
582
583
584
585
...
726
727
728
729
730
731
732


733
734
735
736
737
738
739
740
...
957
958
959
960
961
962
963



964
965
966
967
968
969
970
....
1056
1057
1058
1059
1060
1061
1062





1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
....
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102



1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126




1127
1128
1129
1130
1131
1132
1133
1134
1135
1136



1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149



1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
....
1165
1166
1167
1168
1169
1170
1171




1172
1173
1174
1175
1176
1177
1178
....
1214
1215
1216
1217
1218
1219
1220


1221
1222
1223
1224
1225
1226
1227
....
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

set testprefix wal2

ifcapable !wal {finish_test ; return }


set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
  global sqlite_sync_count
  if {$::tcl_platform(platform) == "windows"} {
    incr sqlite_sync_count $adj
  } {
................................................................................
proc incr_tvfs_hdr {file idx incrval} {
  set ints [set_tvfs_hdr $file]
  set v [lindex $ints $idx]
  incr v $incrval
  lset ints $idx $v
  set_tvfs_hdr $file $ints
}









#-------------------------------------------------------------------------
# Test case wal2-1.*:
#
# Set up a small database containing a single table. The database is not
# checkpointed during the test - all content resides in the log file.
................................................................................
      INSERT INTO t1 VALUES('Chico');
      INSERT INTO t1 VALUES('Harpo');
    COMMIT;
  }
  list [file exists test.db-wal] [file exists test.db-journal]
} {1 0}
do_test wal2-6.3.2 {



  execsql { PRAGMA journal_mode = DELETE }
  file exists test.db-wal
} {0}



do_test wal2-6.3.3 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 VALUES('Groucho');
................................................................................
    if {[string match {#*} $sq]==0} {append S "$sq\n"}
  }

  set ::locks [list]
  do_test wal2-6.4.$tn.1 { execsql $S } $res
  do_test wal2-6.4.$tn.2 { set ::locks  } $L
}



db close
tvfs delete

do_test wal2-6.5.1 {
  sqlite3 db test.db
  execsql {
    PRAGMA auto_vacuum = 0;
................................................................................
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    PRAGMA wal_checkpoint;
    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
  }



  faultsim_save_and_close
} {}
do_test wal2-10.1.2 {
  faultsim_restore_and_reopen
  execsql { SELECT * FROM t1 }
} {1 2 3 4}
do_test wal2-10.1.3 {
................................................................................

#-------------------------------------------------------------------------
# If a connection is required to create a WAL or SHM file, it creates 
# the new files with the same file-system permissions as the database 
# file itself. Test this.
#
if {$::tcl_platform(platform) == "unix"} {





  faultsim_delete_and_reopen
  # Changed on 2012-02-13: umask is deliberately ignored for -wal files.
  #set umask [exec /bin/sh -c umask]
  set umask 0
  

  do_test wal2-12.1 {
    sqlite3 db test.db
    execsql { 
      CREATE TABLE tx(y, z);
      PRAGMA journal_mode = WAL;
    }
    db close
    list [file exists test.db-wal] [file exists test.db-shm]
  } {0 0}
  
  foreach {tn permissions} {
   1 00644
   2 00666
   3 00600
   4 00755
................................................................................
  } {
    set effective [format %.5o [expr $permissions & ~$umask]]
    do_test wal2-12.2.$tn.1 {
      file attributes test.db -permissions $permissions
      string map {o 0} [file attributes test.db -permissions]
    } $permissions
    do_test wal2-12.2.$tn.2 {
      list [file exists test.db-wal] [file exists test.db-shm]
    } {0 0}
    do_test wal2-12.2.$tn.3 {
      sqlite3 db test.db
      execsql { INSERT INTO tx DEFAULT VALUES }
      list [file exists test.db-wal] [file exists test.db-shm]
    } {1 1}
    do_test wal2-12.2.$tn.4 {
      set x [list [file attr test.db-wal -perm] [file attr test.db-shm -perm]]
      string map {o 0} $x
    } [list $effective $effective]
    do_test wal2-12.2.$tn.5 {



      db close
      list [file exists test.db-wal] [file exists test.db-shm]
    } {0 0}
  }
}

#-------------------------------------------------------------------------
# Test the libraries response to discovering that one or more of the
# database, wal or shm files cannot be opened, or can only be opened
# read-only.
#
if {$::tcl_platform(platform) == "unix"} {
  proc perm {} {
    set L [list]
    foreach f {test.db test.db-wal test.db-shm} {
      if {[file exists $f]} {
        lappend L [file attr $f -perm]
      } else {
        lappend L {}
      }
    }
    set L
  }





  faultsim_delete_and_reopen
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    PRAGMA wal_checkpoint;
    INSERT INTO t1 VALUES('3.14', '2.72');
  }
  do_test wal2-13.1.1 {
    list [file exists test.db-shm] [file exists test.db-wal]
  } {1 1}



  faultsim_save_and_close

  foreach {tn db_perm wal_perm shm_perm can_open can_read can_write} {
    2   00644   00644   00644   1   1   1
    3   00644   00400   00644   1   1   0
    4   00644   00644   00400   1   1   0
    5   00400   00644   00644   1   1   0

    7   00644   00000   00644   1   0   0
    8   00644   00644   00000   1   0   0
    9   00000   00644   00644   0   0   0
  } {
    faultsim_restore



    do_test wal2-13.$tn.1 {
      file attr test.db     -perm $db_perm
      file attr test.db-wal -perm $wal_perm
      file attr test.db-shm -perm $shm_perm

      set     L [file attr test.db -perm]
      lappend L [file attr test.db-wal -perm]
      lappend L [file attr test.db-shm -perm]
      string map {o 0} $L
    } [list $db_perm $wal_perm $shm_perm]

    # If $can_open is true, then it should be possible to open a database
    # handle. Otherwise, if $can_open is 0, attempting to open the db
    # handle throws an "unable to open database file" exception.
    #
................................................................................
    set r(1) {0 ok}
    set r(0) {1 {unable to open database file}}
    do_test wal2-13.$tn.2 {
      list [catch {sqlite3 db test.db ; set {} ok} msg] $msg
    } $r($can_open)

    if {$can_open} {





      # If $can_read is true, then the client should be able to read from
      # the database file. If $can_read is false, attempting to read should
      # throw the "unable to open database file" exception. 
      #
      set a(0) {1 {unable to open database file}}
      set a(1) {0 {3.14 2.72}}
................................................................................
  execsql {PRAGMA auto_vacuum = 0; PRAGMA synchronous = FULL;}
  execsql $sql
  do_execsql_test wal2-14.$tn.0 { PRAGMA page_size = 4096 }   {}
  do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0



  do_execsql_test wal2-14.$tn.2 {
    PRAGMA wal_autocheckpoint = 10;
    CREATE TABLE t1(a, b);                -- 2 wal syncs
    INSERT INTO t1 VALUES(1, 2);          -- 2 wal sync
    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
    BEGIN;
................................................................................
    COMMIT;                               -- 2 wal sync
    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
  } {10 0 3 3 0 1 1}

  do_test wal2-14.$tn.3 {
    cond_incr_sync_count 1
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $reslist 0 1]

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0

  do_test wal2-14.$tn.4 {
    execsql { INSERT INTO t1 VALUES(7, zeroblob(12*4096)) }
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $reslist 2 3]

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0

  do_test wal2-14.$tn.5 {
    execsql { PRAGMA wal_autocheckpoint = 1000 }
    execsql { INSERT INTO t1 VALUES(9, 10) }
    execsql { INSERT INTO t1 VALUES(11, 12) }
    execsql { INSERT INTO t1 VALUES(13, 14) }
    db close
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $reslist 4 5]
}

catch { db close }

# PRAGMA checkpoint_fullsync
# PRAGMA fullfsync
# PRAGMA synchronous







>







 







>
>
>
>
>
>
>







 







>
>
>



>
>
>







 







>
>
|







 







>
>
>







 







>
>
>
>
>













|







 







|




|


|



>
>
>

|












|









>
>
>
>








|

>
>
>













>
>
>



|



|







 







>
>
>
>







 







>
>







 







|







|











|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
...
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
...
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
....
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
....
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
....
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
....
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
....
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

set testprefix wal2

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] {finish_test ; return }

set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
  global sqlite_sync_count
  if {$::tcl_platform(platform) == "windows"} {
    incr sqlite_sync_count $adj
  } {
................................................................................
proc incr_tvfs_hdr {file idx incrval} {
  set ints [set_tvfs_hdr $file]
  set v [lindex $ints $idx]
  incr v $incrval
  lset ints $idx $v
  set_tvfs_hdr $file $ints
}

set shmpath test.db-shm
if {[forced_proxy_locking]} {
  sqlite3 db test.db
  set shmpath [execsql { pragma lock_proxy_file }]-shm
  db close
}


#-------------------------------------------------------------------------
# Test case wal2-1.*:
#
# Set up a small database containing a single table. The database is not
# checkpointed during the test - all content resides in the log file.
................................................................................
      INSERT INTO t1 VALUES('Chico');
      INSERT INTO t1 VALUES('Harpo');
    COMMIT;
  }
  list [file exists test.db-wal] [file exists test.db-journal]
} {1 0}
do_test wal2-6.3.2 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql { PRAGMA journal_mode = DELETE }
  file exists test.db-wal
} {0}
do_test wal2-6.3.2.1 {
  execsql { PRAGMA journal_mode; }
} {delete}
do_test wal2-6.3.3 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 VALUES('Groucho');
................................................................................
    if {[string match {#*} $sq]==0} {append S "$sq\n"}
  }

  set ::locks [list]
  do_test wal2-6.4.$tn.1 { execsql $S } $res
  do_test wal2-6.4.$tn.2 { set ::locks  } $L
}
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close
tvfs delete

do_test wal2-6.5.1 {
  sqlite3 db test.db
  execsql {
    PRAGMA auto_vacuum = 0;
................................................................................
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    PRAGMA wal_checkpoint;
    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
  }
  if {[forced_proxy_locking]} {
    forcecopy $shmpath sv_test.db-shm
  }
  faultsim_save_and_close
} {}
do_test wal2-10.1.2 {
  faultsim_restore_and_reopen
  execsql { SELECT * FROM t1 }
} {1 2 3 4}
do_test wal2-10.1.3 {
................................................................................

#-------------------------------------------------------------------------
# If a connection is required to create a WAL or SHM file, it creates 
# the new files with the same file-system permissions as the database 
# file itself. Test this.
#
if {$::tcl_platform(platform) == "unix"} {
  if {[forced_proxy_locking]} {
    # faultsim_delete_and_reopen doesn't know about the shm file redirect...
    forcedelete $shmpath
  }
  
  faultsim_delete_and_reopen
  # Changed on 2012-02-13: umask is deliberately ignored for -wal files.
  #set umask [exec /bin/sh -c umask]
  set umask 0
  

  do_test wal2-12.1 {
    sqlite3 db test.db
    execsql { 
      CREATE TABLE tx(y, z);
      PRAGMA journal_mode = WAL;
    }
    db close
    list [file exists test.db-wal] [file exists $shmpath]
  } {0 0}
  
  foreach {tn permissions} {
   1 00644
   2 00666
   3 00600
   4 00755
................................................................................
  } {
    set effective [format %.5o [expr $permissions & ~$umask]]
    do_test wal2-12.2.$tn.1 {
      file attributes test.db -permissions $permissions
      string map {o 0} [file attributes test.db -permissions]
    } $permissions
    do_test wal2-12.2.$tn.2 {
      list [file exists test.db-wal] [file exists $shmpath]
    } {0 0}
    do_test wal2-12.2.$tn.3 {
      sqlite3 db test.db
      execsql { INSERT INTO tx DEFAULT VALUES }
      list [file exists test.db-wal] [file exists $shmpath]
    } {1 1}
    do_test wal2-12.2.$tn.4 {
      set x [list [file attr test.db-wal -perm] [file attr $shmpath -perm]]
      string map {o 0} $x
    } [list $effective $effective]
    do_test wal2-12.2.$tn.5 {
      ifcapable enable_persist_wal {
        file_control_persist_wal db 0
      }
      db close
      list [file exists test.db-wal] [file exists $shmpath]
    } {0 0}
  }
}

#-------------------------------------------------------------------------
# Test the libraries response to discovering that one or more of the
# database, wal or shm files cannot be opened, or can only be opened
# read-only.
#
if {$::tcl_platform(platform) == "unix"} {
  proc perm {} {
    set L [list]
    foreach f {test.db test.db-wal $shmpath} {
      if {[file exists $f]} {
        lappend L [file attr $f -perm]
      } else {
        lappend L {}
      }
    }
    set L
  }

  if {[forced_proxy_locking]} {
    # faultsim_delete_and_reopen doesn't know about the shm file redirect...
    forcedelete $shmpath
  }
  faultsim_delete_and_reopen
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    PRAGMA wal_checkpoint;
    INSERT INTO t1 VALUES('3.14', '2.72');
  }
  do_test wal2-13.1.1 {
    list [file exists $shmpath] [file exists test.db-wal]
  } {1 1}
  if {[forced_proxy_locking]} {
    forcecopy $shmpath proxysv_test.db-shm 
  }
  faultsim_save_and_close

  foreach {tn db_perm wal_perm shm_perm can_open can_read can_write} {
    2   00644   00644   00644   1   1   1
    3   00644   00400   00644   1   1   0
    4   00644   00644   00400   1   1   0
    5   00400   00644   00644   1   1   0

    7   00644   00000   00644   1   0   0
    8   00644   00644   00000   1   0   0
    9   00000   00644   00644   0   0   0
  } {
    faultsim_restore
    if {[forced_proxy_locking]} {
      forcecopy proxysv_test.db-shm $shmpath  
    }
    do_test wal2-13.$tn.1 {
      file attr test.db     -perm $db_perm
      file attr test.db-wal -perm $wal_perm
      file attr $shmpath -perm $shm_perm

      set     L [file attr test.db -perm]
      lappend L [file attr test.db-wal -perm]
      lappend L [file attr $shmpath -perm]
      string map {o 0} $L
    } [list $db_perm $wal_perm $shm_perm]

    # If $can_open is true, then it should be possible to open a database
    # handle. Otherwise, if $can_open is 0, attempting to open the db
    # handle throws an "unable to open database file" exception.
    #
................................................................................
    set r(1) {0 ok}
    set r(0) {1 {unable to open database file}}
    do_test wal2-13.$tn.2 {
      list [catch {sqlite3 db test.db ; set {} ok} msg] $msg
    } $r($can_open)

    if {$can_open} {
      # Different behavior, because Darwin does an access() call prior
      # to attempting to open the SHM in read/write mode and demotes to
      # read-only if the SHM is read-only.
      if {$tn==4 && $::tcl_platform(os)=="Darwin"} {set can_read 1}

      # If $can_read is true, then the client should be able to read from
      # the database file. If $can_read is false, attempting to read should
      # throw the "unable to open database file" exception. 
      #
      set a(0) {1 {unable to open database file}}
      set a(1) {0 {3.14 2.72}}
................................................................................
  execsql {PRAGMA auto_vacuum = 0; PRAGMA synchronous = FULL;}
  execsql $sql
  do_execsql_test wal2-14.$tn.0 { PRAGMA page_size = 4096 }   {}
  do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0

  set useres $reslist

  do_execsql_test wal2-14.$tn.2 {
    PRAGMA wal_autocheckpoint = 10;
    CREATE TABLE t1(a, b);                -- 2 wal syncs
    INSERT INTO t1 VALUES(1, 2);          -- 2 wal sync
    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
    BEGIN;
................................................................................
    COMMIT;                               -- 2 wal sync
    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
  } {10 0 3 3 0 1 1}

  do_test wal2-14.$tn.3 {
    cond_incr_sync_count 1
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $useres 0 1]

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0

  do_test wal2-14.$tn.4 {
    execsql { INSERT INTO t1 VALUES(7, zeroblob(12*4096)) }
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $useres 2 3]

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0

  do_test wal2-14.$tn.5 {
    execsql { PRAGMA wal_autocheckpoint = 1000 }
    execsql { INSERT INTO t1 VALUES(9, 10) }
    execsql { INSERT INTO t1 VALUES(11, 12) }
    execsql { INSERT INTO t1 VALUES(13, 14) }
    db close
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $useres 4 5]
}

catch { db close }

# PRAGMA checkpoint_fullsync
# PRAGMA fullfsync
# PRAGMA synchronous

Changes to test/wal3.test.

15
16
17
18
19
20
21

22
23
24
25
26
27
28
...
207
208
209
210
211
212
213


214
215
216
217
218
219
220
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }


set a_string_counter 1
proc a_string {n} {
  global a_string_counter
  incr a_string_counter
  string range [string repeat "${a_string_counter}." $n] 1 $n
}
................................................................................
    {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
} {

  proc sync_counter {args} { 
    foreach {method filename id flags} $args break
    lappend ::syncs [file tail $filename] $flags
  }


  do_test wal3-3.$tn {
    forcedelete test.db test.db-wal test.db-journal
  
    testvfs T
    T filter {} 
    T script sync_counter
    sqlite3 db test.db -vfs T
................................................................................
    execsql {
      CREATE TABLE x(y);
      INSERT INTO x VALUES('z');
      PRAGMA wal_checkpoint;
    }
    T filter {}
    set ::syncs
  } $synccount

  db close
  T delete
}


#-------------------------------------------------------------------------







>







 







>
>







 







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }
if ![wal_is_ok] {finish_test ; return }

set a_string_counter 1
proc a_string {n} {
  global a_string_counter
  incr a_string_counter
  string range [string repeat "${a_string_counter}." $n] 1 $n
}
................................................................................
    {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
} {

  proc sync_counter {args} { 
    foreach {method filename id flags} $args break
    lappend ::syncs [file tail $filename] $flags
  }
  set usecount $synccount

  do_test wal3-3.$tn {
    forcedelete test.db test.db-wal test.db-journal
  
    testvfs T
    T filter {} 
    T script sync_counter
    sqlite3 db test.db -vfs T
................................................................................
    execsql {
      CREATE TABLE x(y);
      INSERT INTO x VALUES('z');
      PRAGMA wal_checkpoint;
    }
    T filter {}
    set ::syncs
  } $usecount

  db close
  T delete
}


#-------------------------------------------------------------------------

Changes to test/wal4.test.

12
13
14
15
16
17
18




19
20
21
22
23
24
25
# result in database corruption
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }





do_test wal4-1.1 {
  execsql {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES(1);
    INSERT INTO t1 VALUES(2);







>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# result in database corruption
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] || [path_is_dos "."]} {
  finish_test 
  return 
}

do_test wal4-1.1 {
  execsql {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES(1);
    INSERT INTO t1 VALUES(2);

Changes to test/wal5.test.

14
15
16
17
18
19
20

21
22
23
24
25
26
27
..
76
77
78
79
80
81
82





83
84
85
86
87
88
89
...
339
340
341
342
343
344
345





346
347
348
349
350
351
352
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }

do_not_use_codec

set testprefix wal5

proc db_page_count  {{file test.db}} { expr [file size $file] / 1024 }
proc wal_page_count {{file test.db}} { wal_frame_count ${file}-wal 1024 }

................................................................................
    proc busyhandler {n} {
      incr ::nBusyHandler 
      eval $::busy_handler_script
      return 0
    }

    proc reopen_all {} {





      code1 {db close}
      code2 {db2 close}
      code3 {db3 close}

      code1 {sqlite3 db test.db}
      code2 {sqlite3 db2 test.db}
      code3 {sqlite3 db3 test.db}
................................................................................

    do_test 3.$tn.2 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.3 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.4 { code3 { do_wal_checkpoint db3 } } {0 2 2}






    code1 {db  close}
    code2 {db2 close}
    code3 {db3 close}

    code1 {sqlite3 db  test.db}
    code2 {sqlite3 db2 test.db}
    code3 {sqlite3 db3 test.db}







>







 







>
>
>
>
>







 







>
>
>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
..
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }
do_not_use_codec

set testprefix wal5

proc db_page_count  {{file test.db}} { expr [file size $file] / 1024 }
proc wal_page_count {{file test.db}} { wal_frame_count ${file}-wal 1024 }

................................................................................
    proc busyhandler {n} {
      incr ::nBusyHandler 
      eval $::busy_handler_script
      return 0
    }

    proc reopen_all {} {
      ifcapable enable_persist_wal {
        code1 { file_control_persist_wal db 0 }
        code2 { file_control_persist_wal db2 0 }
        code3 { file_control_persist_wal db3 0 }
      }
      code1 {db close}
      code2 {db2 close}
      code3 {db3 close}

      code1 {sqlite3 db test.db}
      code2 {sqlite3 db2 test.db}
      code3 {sqlite3 db3 test.db}
................................................................................

    do_test 3.$tn.2 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.3 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.4 { code3 { do_wal_checkpoint db3 } } {0 2 2}

    ifcapable enable_persist_wal {
      code1 { file_control_persist_wal db 0 }
      code2 { file_control_persist_wal db2 0 }
      code3 { file_control_persist_wal db3 0 }
    }
    code1 {db  close}
    code2 {db2 close}
    code3 {db3 close}

    code1 {sqlite3 db  test.db}
    code2 {sqlite3 db2 test.db}
    code3 {sqlite3 db3 test.db}

Changes to test/wal6.test.

16
17
18
19
20
21
22


23
24
25
26
27
28
29
set testdir [file dirname $argv0]
set testprefix wal6
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }



#-------------------------------------------------------------------------
# Changing to WAL mode in one connection forces the change in others.
#
db close
forcedelete test.db








>
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
set testdir [file dirname $argv0]
set testprefix wal6
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }

if { ![wal_is_ok] } {finish_test ; return }

#-------------------------------------------------------------------------
# Changing to WAL mode in one connection forces the change in others.
#
db close
forcedelete test.db

Changes to test/wal7.test.

12
13
14
15
16
17
18

19
20
21
22
23
24
25
# focus of this file is testing the PRAGMA journal_size_limit when
# in WAL mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !wal {finish_test ; return }


# Case 1:  No size limit.  Journal can get large.
#
do_test wal7-1.0 {
  db close
  forcedelete test.db
  sqlite3 db test.db







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# focus of this file is testing the PRAGMA journal_size_limit when
# in WAL mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

# Case 1:  No size limit.  Journal can get large.
#
do_test wal7-1.0 {
  db close
  forcedelete test.db
  sqlite3 db test.db

Changes to test/wal8.test.

22
23
24
25
26
27
28

29

30
31
32
33
34
35
36
# size from the database file as soon as it is opened (even before the
# first read transaction is executed), and the "PRAGMA page_size = XXX"
# is a no-op.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix wal8

ifcapable !wal {finish_test ; return }

do_not_use_codec

db close
forcedelete test.db test.db-wal

sqlite3 db test.db
sqlite3 db2 test.db







>

>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# size from the database file as soon as it is opened (even before the
# first read transaction is executed), and the "PRAGMA page_size = XXX"
# is a no-op.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix wal8

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }
do_not_use_codec

db close
forcedelete test.db test.db-wal

sqlite3 db test.db
sqlite3 db2 test.db

Changes to test/wal_common.tcl.

28
29
30
31
32
33
34














35
36
37
38
39
40
41
  upvar $ckv1 c1
  upvar $ckv2 c2
  foreach {v1 v2} $intlist {
    set c1 [expr {($c1 + $v1 + $c2)&0xFFFFFFFF}]
    set c2 [expr {($c2 + $v2 + $c1)&0xFFFFFFFF}]
  }
}
















# This proc calculates checksums in the same way as those used by SQLite 
# in WAL files. If the $endian argument is "big", then checksums are
# calculated by interpreting data as an array of big-endian integers. If
# it is "little", data is interpreted as an array of little-endian integers.
#







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







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
  upvar $ckv1 c1
  upvar $ckv2 c2
  foreach {v1 v2} $intlist {
    set c1 [expr {($c1 + $v1 + $c2)&0xFFFFFFFF}]
    set c2 [expr {($c2 + $v2 + $c1)&0xFFFFFFFF}]
  }
}

# If the synchronous mode for the main database of db handle $db
# is either OFF or NORMAL, return $nRight. Otherwise, if it is
# FULL, return $nWrite+$nTrans.
#
proc wal_frames {db nWrite nTrans} {
  set nRet $nWrite
  switch -- [$db one {PRAGMA main.synchronous}] {
    0 { }
    1 { }
    default { incr nRet $nTrans }
  }
  set nRet
}


# This proc calculates checksums in the same way as those used by SQLite 
# in WAL files. If the $endian argument is "big", then checksums are
# calculated by interpreting data as an array of big-endian integers. If
# it is "little", data is interpreted as an array of little-endian integers.
#

Changes to test/walbak.test.

17
18
19
20
21
22
23

24
25
26
27
28
29
30
...
320
321
322
323
324
325
326



327
328
329
330
331
332
333
334



335
336
337
338
339
340
341
source $testdir/tester.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl

do_not_use_codec

ifcapable !wal {finish_test ; return }



# Test organization:
# 
#   walback-1.*: Simple tests.
#
#   walback-2.*: Test backups when the source db is modified mid-backup.
................................................................................
  catch { db close } 
  catch { db2 close } 
  forcedelete test.db test.db2

  do_test walbak-4.$tn.1 {
    sqlite3 db test.db
    db eval "PRAGMA journal_mode = $src"



    db eval {
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES('I', 'II');
      INSERT INTO t1 VALUES('III', 'IV');
    }

    sqlite3 db2 test.db2
    db2 eval "PRAGMA journal_mode = $dest"



    db2 eval {
      CREATE TABLE t2(x, y);
      INSERT INTO t2 VALUES('1', '2');
      INSERT INTO t2 VALUES('3', '4');
    }
  } {}








>







 







>
>
>








>
>
>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
source $testdir/tester.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl

do_not_use_codec

ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] } { finish_test ; return }


# Test organization:
# 
#   walback-1.*: Simple tests.
#
#   walback-2.*: Test backups when the source db is modified mid-backup.
................................................................................
  catch { db close } 
  catch { db2 close } 
  forcedelete test.db test.db2

  do_test walbak-4.$tn.1 {
    sqlite3 db test.db
    db eval "PRAGMA journal_mode = $src"
    ifcapable enable_persist_wal {
      file_control_persist_wal db 0
    }
    db eval {
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES('I', 'II');
      INSERT INTO t1 VALUES('III', 'IV');
    }

    sqlite3 db2 test.db2
    db2 eval "PRAGMA journal_mode = $dest"
    ifcapable enable_persist_wal {
      file_control_persist_wal db2 0
    }
    db2 eval {
      CREATE TABLE t2(x, y);
      INSERT INTO t2 VALUES('1', '2');
      INSERT INTO t2 VALUES('3', '4');
    }
  } {}

Changes to test/walbig.test.

17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
32
33




34
35
36
37
38
39
40
set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !wal {
  finish_test
  return
}


# Do not use a codec for this file, as the database is manipulated using
# external methods (the [fake_big_file] and [hexio_write] commands).
#
do_not_use_codec

# If SQLITE_DISABLE_LFS is defined, omit this file.
ifcapable !lfs {
  finish_test
  return




}

set a_string_counter 1
proc a_string {n} {
  incr ::a_string_counter
  string range [string repeat "${::a_string_counter}." $n] 1 $n
}







>










>
>
>
>







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
set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !wal {
  finish_test
  return
}
if ![wal_is_ok] { finish_test; return }

# Do not use a codec for this file, as the database is manipulated using
# external methods (the [fake_big_file] and [hexio_write] commands).
#
do_not_use_codec

# If SQLITE_DISABLE_LFS is defined, omit this file.
ifcapable !lfs {
  finish_test
  return
}
if { ![wal_is_ok] } {
  finish_test 
  return 
}

set a_string_counter 1
proc a_string {n} {
  incr ::a_string_counter
  string range [string repeat "${::a_string_counter}." $n] 1 $n
}

Changes to test/walcksum.test.

12
13
14
15
16
17
18

19
20
21
22
23
24
25

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

ifcapable !wal {finish_test ; return }


# Read and return the contents of file $filename. Treat the content as
# binary data.
#
proc readfile {filename} {
  set fd [open $filename]
  fconfigure $fd -encoding binary







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

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

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

# Read and return the contents of file $filename. Treat the content as
# binary data.
#
proc readfile {filename} {
  set fd [open $filename]
  fconfigure $fd -encoding binary

Changes to test/walcrash.test.

24
25
26
27
28
29
30

31
32
33
34
35
36
37
# walcrash-3.*: Recover multiple databases where the failed transaction 
#               was a multi-file transaction.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !wal {finish_test ; return }


db close

set seed 0
set REPEATS 100

# walcrash-1.*







>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# walcrash-3.*: Recover multiple databases where the failed transaction 
#               was a multi-file transaction.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

db close

set seed 0
set REPEATS 100

# walcrash-1.*

Changes to test/walcrash2.test.

12
13
14
15
16
17
18

19
20
21
22
23
24
25


set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }



#-------------------------------------------------------------------------
# This test case demonstrates a flaw in the wal-index manipulation that
# existed at one point: If a process crashes mid-transaction, it may have
# already added some entries to one of the hash-tables in the wal-index.
# If the transaction were to be explicitly rolled back at this point, the







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26


set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] } { finish_test ; return }


#-------------------------------------------------------------------------
# This test case demonstrates a flaw in the wal-index manipulation that
# existed at one point: If a process crashes mid-transaction, it may have
# already added some entries to one of the hash-tables in the wal-index.
# If the transaction were to be explicitly rolled back at this point, the

Changes to test/walcrash3.test.

14
15
16
17
18
19
20


21
22
23
24
25
26
27
# truncates the WAL file if "PRAGMA journal_size_limit" is configured.
#

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

ifcapable !wal {finish_test ; return }


set testprefix walcrash3

db close
testvfs tvfs
tvfs filter {xTruncate xWrite}
tvfs script tvfs_callback
proc tvfs_callback {args} {}







>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# truncates the WAL file if "PRAGMA journal_size_limit" is configured.
#

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

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

set testprefix walcrash3

db close
testvfs tvfs
tvfs filter {xTruncate xWrite}
tvfs script tvfs_callback
proc tvfs_callback {args} {}

Changes to test/walfault.test.

15
16
17
18
19
20
21

22
23
24
25
26
27
28

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

ifcapable !wal {finish_test ; return }


#-------------------------------------------------------------------------
# This test case, walfault-1-*, simulates faults while executing a
#
#   PRAGMA journal_mode = WAL;
#
# statement immediately after creating a new database.







>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

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

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

#-------------------------------------------------------------------------
# This test case, walfault-1-*, simulates faults while executing a
#
#   PRAGMA journal_mode = WAL;
#
# statement immediately after creating a new database.

Changes to test/walhook.test.

18
19
20
21
22
23
24

25
26
27
28
29
30
31
..
67
68
69
70
71
72
73



74
75



76
77
78
79
80
81
82
#

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

ifcapable !wal {finish_test ; return }


set ::wal_hook [list]
proc wal_hook {zDb nEntry} {
  lappend ::wal_hook $zDb $nEntry
  return 0
}
db wal_hook wal_hook
................................................................................
    return 0
  }
  execsql { CREATE TABLE t3(a PRIMARY KEY, b) }
  file size test.db
} [expr 6*1024]

db2 close



db close
sqlite3 db test.db



do_test walhook-2.1 {
  execsql { PRAGMA synchronous = NORMAL }
  execsql { PRAGMA wal_autocheckpoint }
} {1000}
do_test walhook-2.2 {
  execsql { PRAGMA wal_autocheckpoint = 10}
} {10}







>







 







>
>
>


>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#

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

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

set ::wal_hook [list]
proc wal_hook {zDb nEntry} {
  lappend ::wal_hook $zDb $nEntry
  return 0
}
db wal_hook wal_hook
................................................................................
    return 0
  }
  execsql { CREATE TABLE t3(a PRIMARY KEY, b) }
  file size test.db
} [expr 6*1024]

db2 close
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close
sqlite3 db test.db
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
do_test walhook-2.1 {
  execsql { PRAGMA synchronous = NORMAL }
  execsql { PRAGMA wal_autocheckpoint }
} {1000}
do_test walhook-2.2 {
  execsql { PRAGMA wal_autocheckpoint = 10}
} {10}

Changes to test/walmode.test.

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
..
64
65
66
67
68
69
70



71
72
73
74
75
76
77
..
80
81
82
83
84
85
86



87
88
89
90
91
92
93
...
102
103
104
105
106
107
108



109
110
111
112
113
114
115
...
129
130
131
132
133
134
135



136
137
138
139
140
141
142
...
146
147
148
149
150
151
152



153
154
155
156
157
158
159
...
299
300
301
302
303
304
305



306
307
308
309
310
311
312
  do_test walmode-0.3 {
    execsql { PRAGMA main.journal_mode }
  } {delete}

  finish_test
  return
}















do_test walmode-1.1 {
  set sqlite_sync_count 0
  execsql { PRAGMA page_size = 1024 }
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-1.2 {
  file size test.db
} {1024}

if {[atomic_batch_write test.db]==0} {






  set expected_sync_count 3

  if {$::tcl_platform(platform)!="windows"} {
    ifcapable dirsync {
      incr expected_sync_count
    }
  }
  do_test walmode-1.3 {
    set sqlite_sync_count
  } $expected_sync_count
}

do_test walmode-1.4 {
................................................................................
  execsql { CREATE TABLE t1(a, b) }
  file size test.db
} {1024}
do_test walmode-1.6 {
  file exists test.db-wal
} {1}
do_test walmode-1.7 {



  db close
  file exists test.db-wal
} {0}

# There is now a database file with the read and write versions set to 2
# in the file system. This file should default to WAL mode.
#
................................................................................
  file exists test.db-wal
} {0}
do_test walmode-2.2 {
  execsql { SELECT * FROM sqlite_master }
  file exists test.db-wal
} {1}
do_test walmode-2.3 {



  db close
  file exists test.db-wal
} {0}

# If the first statement executed is "PRAGMA journal_mode = wal", and
# the file is already configured for WAL (read and write versions set
# to 2), then there should be no need to write the database. The 
................................................................................
  list $sqlite_sync_count [file exists test.db-wal] [file size test.db-wal]
} {0 1 0}

# Test that changing back to journal_mode=persist works.
#
do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }



  execsql { PRAGMA journal_mode = persist }
} {persist}
if {[atomic_batch_write test.db]==0} {
  do_test walmode-4.2 {
    list [file exists test.db-journal] [file exists test.db-wal]
  } {1 0}
}
................................................................................

# Test that nothing goes wrong if a connection is prevented from changing
# from WAL to rollback mode because a second connection has the database
# open. Or from rollback to WAL.
#
do_test walmode-4.6 {
  sqlite3 db2 test.db



  execsql { PRAGMA main.journal_mode } db2
} {delete}
do_test walmode-4.7 {
  execsql { PRAGMA main.journal_mode = wal } db
} {wal}
do_test walmode-4.8 {
  execsql { SELECT * FROM t1 } db2
................................................................................
} {1 {database is locked}}
do_test walmode-4.10 {
  execsql { PRAGMA main.journal_mode } db
} {wal}

do_test walmode-4.11 {
  db2 close



  execsql { PRAGMA journal_mode = delete } db
} {delete}
do_test walmode-4.12 {
  execsql { PRAGMA main.journal_mode } db
} {delete}
do_test walmode-4.13 {
  list [file exists test.db-journal] [file exists test.db-wal]
................................................................................
# Test the effect of a "PRAGMA journal_mode" command being the first 
# thing executed by a new connection. This means that the schema is not
# loaded when sqlite3_prepare_v2() is called to compile the statement.
#
do_test walmode-7.0 {
  forcedelete test.db
  sqlite3 db test.db



  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
  }
} {wal}
foreach {tn sql result} {
  1  "PRAGMA journal_mode"                wal







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










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







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







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
..
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  do_test walmode-0.3 {
    execsql { PRAGMA main.journal_mode }
  } {delete}

  finish_test
  return
}
if { ![wal_is_ok] && ![path_is_dos "."]} {
  do_test walmode-0.1 {
    execsql { PRAGMA journal_mode = wal }
  } {delete}
  do_test walmode-0.2 {
    execsql { PRAGMA main.journal_mode = wal }
  } {delete}
  do_test walmode-0.3 {
    execsql { PRAGMA main.journal_mode }
  } {delete}

  finish_test
  return
}

do_test walmode-1.1 {
  set sqlite_sync_count 0
  execsql { PRAGMA page_size = 1024 }
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-1.2 {
  file size test.db
} {1024}

# Determine how many sync() calls to expect from the "journal_mode=WAL" 
# command above. Note that if DEFAULT_WAL_SAFETYLEVEL is defined, the
# safety-level may have been modified while compiling the "journal_mode=WAL"
# statement.
switch -- [db eval {PRAGMA main.synchronous}] {
  0        { set expected_sync_count 0 }
  1        { set expected_sync_count 2 }
  default  { set expected_sync_count 3 }
}
if {$::tcl_platform(platform)!="windows"} {
  ifcapable dirsync {
    incr expected_sync_count

  }
  do_test walmode-1.3 {
    set sqlite_sync_count
  } $expected_sync_count
}

do_test walmode-1.4 {
................................................................................
  execsql { CREATE TABLE t1(a, b) }
  file size test.db
} {1024}
do_test walmode-1.6 {
  file exists test.db-wal
} {1}
do_test walmode-1.7 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  file exists test.db-wal
} {0}

# There is now a database file with the read and write versions set to 2
# in the file system. This file should default to WAL mode.
#
................................................................................
  file exists test.db-wal
} {0}
do_test walmode-2.2 {
  execsql { SELECT * FROM sqlite_master }
  file exists test.db-wal
} {1}
do_test walmode-2.3 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  file exists test.db-wal
} {0}

# If the first statement executed is "PRAGMA journal_mode = wal", and
# the file is already configured for WAL (read and write versions set
# to 2), then there should be no need to write the database. The 
................................................................................
  list $sqlite_sync_count [file exists test.db-wal] [file size test.db-wal]
} {0 1 0}

# Test that changing back to journal_mode=persist works.
#
do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql { PRAGMA journal_mode = persist }
} {persist}
if {[atomic_batch_write test.db]==0} {
  do_test walmode-4.2 {
    list [file exists test.db-journal] [file exists test.db-wal]
  } {1 0}
}
................................................................................

# Test that nothing goes wrong if a connection is prevented from changing
# from WAL to rollback mode because a second connection has the database
# open. Or from rollback to WAL.
#
do_test walmode-4.6 {
  sqlite3 db2 test.db
  ifcapable enable_persist_wal {
    file_control_persist_wal db2 0
  }
  execsql { PRAGMA main.journal_mode } db2
} {delete}
do_test walmode-4.7 {
  execsql { PRAGMA main.journal_mode = wal } db
} {wal}
do_test walmode-4.8 {
  execsql { SELECT * FROM t1 } db2
................................................................................
} {1 {database is locked}}
do_test walmode-4.10 {
  execsql { PRAGMA main.journal_mode } db
} {wal}

do_test walmode-4.11 {
  db2 close
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql { PRAGMA journal_mode = delete } db
} {delete}
do_test walmode-4.12 {
  execsql { PRAGMA main.journal_mode } db
} {delete}
do_test walmode-4.13 {
  list [file exists test.db-journal] [file exists test.db-wal]
................................................................................
# Test the effect of a "PRAGMA journal_mode" command being the first 
# thing executed by a new connection. This means that the schema is not
# loaded when sqlite3_prepare_v2() is called to compile the statement.
#
do_test walmode-7.0 {
  forcedelete test.db
  sqlite3 db test.db
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
  }
} {wal}
foreach {tn sql result} {
  1  "PRAGMA journal_mode"                wal

Changes to test/walnoshm.test.

13
14
15
16
17
18
19

20
21
22
23
24
25
26
..
49
50
51
52
53
54
55



56
57
58
59
60
61
62
# using the xShm primitives if the connection is in exclusive-mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix walnoshm
ifcapable !wal {finish_test ; return }


db close
testvfs tvfsshm
testvfs tvfs -default 1 -iversion 1 
sqlite3 db test.db

#--------------------------------------------------------------------------
................................................................................
do_test 1.5 { file exists test.db-wal } {1}

do_execsql_test 1.6 { INSERT INTO t1 VALUES(3, 4) }

do_execsql_test 1.7 {
  PRAGMA locking_mode = normal;
} {exclusive}



do_execsql_test 1.8 {
  PRAGMA journal_mode = delete;
  PRAGMA main.locking_mode;
} {delete exclusive}
do_execsql_test 1.9 {
  PRAGMA locking_mode = normal;
} {normal}







>







 







>
>
>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# using the xShm primitives if the connection is in exclusive-mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix walnoshm
ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

db close
testvfs tvfsshm
testvfs tvfs -default 1 -iversion 1 
sqlite3 db test.db

#--------------------------------------------------------------------------
................................................................................
do_test 1.5 { file exists test.db-wal } {1}

do_execsql_test 1.6 { INSERT INTO t1 VALUES(3, 4) }

do_execsql_test 1.7 {
  PRAGMA locking_mode = normal;
} {exclusive}
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
do_execsql_test 1.8 {
  PRAGMA journal_mode = delete;
  PRAGMA main.locking_mode;
} {delete exclusive}
do_execsql_test 1.9 {
  PRAGMA locking_mode = normal;
} {normal}

Changes to test/walpersist.test.

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
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
source $testdir/lock_common.tcl
set ::testprefix walpersist

ifcapable !wal {
  finish_test
  return
}







do_test walpersist-1.0 {
  db eval {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(randomblob(5000));
  }
  file exists test.db-wal
} {1}
do_test walpersist-1.1 {
  file exists test.db-shm
} {1}

do_test walpersist-1.2 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]





} {1 0 0}

do_test walpersist-1.3 {
  sqlite3 db test.db
  db eval {SELECT length(a) FROM t1}
} {5000}
do_test walpersist-1.4 {
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}

do_test walpersist-1.5 {
  file_control_persist_wal db -1




} {0 0}

do_test walpersist-1.6 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.7 {
  file_control_persist_wal db -1
} {0 1}
do_test walpersist-1.8 {
................................................................................
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.10 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.11 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}

# Make sure the journal_size_limit works to limit the size of the
# persisted wal file.  In persistent-wal mode, any non-negative
# journal_size_limit causes the WAL file to be truncated to zero bytes
# when closing.
#
forcedelete test.db test.db-shm test.db-wal
do_test walpersist-2.1 {
  sqlite3 db test.db
  db eval {
    PRAGMA journal_mode=WAL;
    PRAGMA wal_autocheckpoint=OFF;
    PRAGMA journal_size_limit=12000;
    CREATE TABLE t1(x);
................................................................................
do_test walpersist-2.3 {
  sqlite3 db test.db
  execsql { PRAGMA integrity_check }
} {ok}

do_test 3.1 {
  catch {db close}
  forcedelete test.db test.db-shm test.db-wal
  sqlite3 db test.db
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint=128;
    PRAGMA journal_size_limit=16384;
    CREATE TABLE t1(a, b, PRIMARY KEY(a, b));







>
>
>
>
>
>










|

>
|
|
|
>
>
>
>
>
|
>





|

>
|
|
>
>
>
>
|
>







 







|







|







 







|







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
..
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
source $testdir/lock_common.tcl
set ::testprefix walpersist

ifcapable !wal {
  finish_test
  return
}
if ![wal_is_ok] { finish_test; return }

set shmpath test.db-shm
if {[forced_proxy_locking]} {
  set shmpath [execsql { pragma lock_proxy_file }]-shm
}

do_test walpersist-1.0 {
  db eval {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(randomblob(5000));
  }
  file exists test.db-wal
} {1}
do_test walpersist-1.1 {
  file exists $shmpath
} {1}
ifcapable enable_persist_wal {
  do_test walpersist-1.2-on {
    db close
    list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
  } {1 1 1}
} {
  do_test walpersist-1.2-off {
    db close
    list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
  } {1 0 0}
}
do_test walpersist-1.3 {
  sqlite3 db test.db
  db eval {SELECT length(a) FROM t1}
} {5000}
do_test walpersist-1.4 {
  list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
} {1 1 1}
ifcapable enable_persist_wal {
  do_test walpersist-1.5-on {
    file_control_persist_wal db -1
  } {0 1}
} {
  do_test walpersist-1.5-off {
    file_control_persist_wal db -1
  } {0 0}
}
do_test walpersist-1.6 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.7 {
  file_control_persist_wal db -1
} {0 1}
do_test walpersist-1.8 {
................................................................................
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.10 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.11 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
} {1 1 1}

# Make sure the journal_size_limit works to limit the size of the
# persisted wal file.  In persistent-wal mode, any non-negative
# journal_size_limit causes the WAL file to be truncated to zero bytes
# when closing.
#
forcedelete test.db $shmpath test.db-wal
do_test walpersist-2.1 {
  sqlite3 db test.db
  db eval {
    PRAGMA journal_mode=WAL;
    PRAGMA wal_autocheckpoint=OFF;
    PRAGMA journal_size_limit=12000;
    CREATE TABLE t1(x);
................................................................................
do_test walpersist-2.3 {
  sqlite3 db test.db
  execsql { PRAGMA integrity_check }
} {ok}

do_test 3.1 {
  catch {db close}
  forcedelete test.db $shmpath test.db-wal
  sqlite3 db test.db
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint=128;
    PRAGMA journal_size_limit=16384;
    CREATE TABLE t1(a, b, PRIMARY KEY(a, b));

Changes to test/walro.test.

26
27
28
29
30
31
32








33
34
35
36
37
38
39
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
..
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
...
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
...
293
294
295
296
297
298
299

































































300

# And only if the build is WAL-capable.
#
ifcapable !wal {
  finish_test
  return
}









do_multiclient_test tn {
  
  # Close all connections and delete the database.
  #
  code1 { db close  }
  code2 { db2 close }
................................................................................
    code2 { sqlite3 db2 test.db }
    sql2 { 
      PRAGMA auto_vacuum = 0;
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(x, y);
      INSERT INTO t1 VALUES('a', 'b');
    }
    file exists test.db-shm
  } {1}

  do_test 1.1.2 {
    file attributes test.db-shm -permissions r--r--r--
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
  } {}

  do_test 1.1.3 { sql1 "SELECT * FROM t1" }                {a b}
  do_test 1.1.4 { sql2 "INSERT INTO t1 VALUES('c', 'd')" } {}
  do_test 1.1.5 { sql1 "SELECT * FROM t1" }                {a b c d}

................................................................................
  } {}
  do_test 1.1.12 { sql1 "SELECT * FROM t1" }                {a b c d e f g h}
  do_test 1.1.13  { sql2 "INSERT INTO t1 VALUES('i', 'j')" } {}

  do_test 1.2.1 {
    code2 { db2 close }
    code1 { db close }
    list [file exists test.db-wal] [file exists test.db-shm]
  } {1 1}

  do_test 1.2.2 {
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    list [catch { sql1 { SELECT * FROM t1 } } msg] $msg
  } {0 {a b c d e f g h i j}}

  do_test 1.2.3 {
    code1 { db close }
    file attributes test.db-shm -permissions rw-r--r--
    hexio_write test.db-shm 0 01020304 
    file attributes test.db-shm -permissions r--r--r--
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM t1 }
  } {0 {a b c d e f g h i j}}
  do_test 1.2.4 {
    code1 { sqlite3_extended_errcode db } 
  } {SQLITE_OK}

  do_test 1.2.5 {
    file attributes test.db-shm -permissions rw-r--r--
    code2 { sqlite3 db2 test.db }
    sql2 "SELECT * FROM t1" 
  } {a b c d e f g h i j}
  file attributes test.db-shm -permissions r--r--r--
  do_test 1.2.6 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j}

  do_test 1.2.7 { 
    sql2 {
      PRAGMA wal_checkpoint;
      INSERT INTO t1 VALUES('k', 'l');
    }
................................................................................
    code1 { sqlite3 db test.db }
    csql1 { SELECT * FROM t1 }
  } {0 {a b c d e f g h i j k l}}

  # Also test that if the -shm file can be opened for read/write access,
  # it is not if readonly_shm=1 is present in the URI.
  do_test 1.3.2.1 {




    code1 { db close }
    code2 { db2 close }
    file exists test.db-shm
  } {0}
  do_test 1.3.2.2 {
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM sqlite_master }
  } {1 {unable to open database file}}
  do_test 1.3.2.3 {
    code1 { db close }
    close [open test.db-shm w]
    file attributes test.db-shm -permissions r--r--r--
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM t1 }
  } {0 {a b c d e f g h i j k l}}
  do_test 1.3.2.4 {
    code1 { sqlite3_extended_errcode db } 
  } {SQLITE_OK}

................................................................................

  do_test 2.1.5 {
    code1 { db close }
    code1 { tv delete }
  } {}
}


































































finish_test







>
>
>
>
>
>
>
>







 







|



|







 







|









|
|
|








|



|







 







>
>
>
>


|







|
|







 







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

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
..
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
...
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
...
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
...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
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

# And only if the build is WAL-capable.
#
ifcapable !wal {
  finish_test
  return
}
if ![wal_is_ok] { finish_test; return }

set shmpath test.db-shm
if {[forced_proxy_locking]} {
  sqlite3 db test.db
  set shmpath [execsql { pragma lock_proxy_file }]-shm
  db close
}

do_multiclient_test tn {
  
  # Close all connections and delete the database.
  #
  code1 { db close  }
  code2 { db2 close }
................................................................................
    code2 { sqlite3 db2 test.db }
    sql2 { 
      PRAGMA auto_vacuum = 0;
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(x, y);
      INSERT INTO t1 VALUES('a', 'b');
    }
    file exists $shmpath
  } {1}

  do_test 1.1.2 {
    file attributes $shmpath -permissions r--r--r--
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
  } {}

  do_test 1.1.3 { sql1 "SELECT * FROM t1" }                {a b}
  do_test 1.1.4 { sql2 "INSERT INTO t1 VALUES('c', 'd')" } {}
  do_test 1.1.5 { sql1 "SELECT * FROM t1" }                {a b c d}

................................................................................
  } {}
  do_test 1.1.12 { sql1 "SELECT * FROM t1" }                {a b c d e f g h}
  do_test 1.1.13  { sql2 "INSERT INTO t1 VALUES('i', 'j')" } {}

  do_test 1.2.1 {
    code2 { db2 close }
    code1 { db close }
    list [file exists test.db-wal] [file exists $shmpath]
  } {1 1}

  do_test 1.2.2 {
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    list [catch { sql1 { SELECT * FROM t1 } } msg] $msg
  } {0 {a b c d e f g h i j}}

  do_test 1.2.3 {
    code1 { db close }
    file attributes $shmpath -permissions rw-r--r--
    hexio_write $shmpath 0 01020304
    file attributes $shmpath -permissions r--r--r--
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM t1 }
  } {0 {a b c d e f g h i j}}
  do_test 1.2.4 {
    code1 { sqlite3_extended_errcode db } 
  } {SQLITE_OK}

  do_test 1.2.5 {
    file attributes $shmpath -permissions rw-r--r--
    code2 { sqlite3 db2 test.db }
    sql2 "SELECT * FROM t1" 
  } {a b c d e f g h i j}
  file attributes $shmpath -permissions r--r--r--
  do_test 1.2.6 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j}

  do_test 1.2.7 { 
    sql2 {
      PRAGMA wal_checkpoint;
      INSERT INTO t1 VALUES('k', 'l');
    }
................................................................................
    code1 { sqlite3 db test.db }
    csql1 { SELECT * FROM t1 }
  } {0 {a b c d e f g h i j k l}}

  # Also test that if the -shm file can be opened for read/write access,
  # it is not if readonly_shm=1 is present in the URI.
  do_test 1.3.2.1 {
    ifcapable enable_persist_wal {
      code1 { file_control_persist_wal db 0 }
      code2 { file_control_persist_wal db2 0 }
    }
    code1 { db close }
    code2 { db2 close }
    file exists $shmpath
  } {0}
  do_test 1.3.2.2 {
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM sqlite_master }
  } {1 {unable to open database file}}
  do_test 1.3.2.3 {
    code1 { db close }
    close [open $shmpath w]
    file attributes $shmpath -permissions r--r--r--
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM t1 }
  } {0 {a b c d e f g h i j k l}}
  do_test 1.3.2.4 {
    code1 { sqlite3_extended_errcode db } 
  } {SQLITE_OK}

................................................................................

  do_test 2.1.5 {
    code1 { db close }
    code1 { tv delete }
  } {}
}

forcedelete $shmpath

if {$tcl_platform(os)=="Darwin"} {
  ifcapable enable_persist_wal {

    #--------------------------------------------------------------------------
    
    catch {db2 close}
    reset_db
    do_execsql_test 3.1 {
      CREATE TABLE t1(a, b);
      PRAGMA journal_mode = wal;
      INSERT INTO t1 VALUES(1, 2);
    } {wal}
    db_save
    db close
    db_restore
    
    sqlite3 db test.db -readonly 1
    
    do_execsql_test 3.2 { SELECT * FROM t1 } {1 2}
    do_catchsql_test 3.3 { 
      INSERT INTO t1 VALUES(3, 4) 
    } {1 {attempt to write a readonly database}}
    
    sqlite3 db2 test.db
    do_test 3.4 { 
      db2 eval { INSERT INTO t1 VALUES(3, 4) }
    } {}
    do_execsql_test 3.5 { SELECT * FROM t1 } {1 2 3 4}
    
    db close
    db2 close
    db_restore
    file attributes $shmpath -permissions r--r--r--
    sqlite3 db test.db -readonly 1
    do_execsql_test 3.6 { SELECT * FROM t1 } {1 2}
    
    db close
    db_restore
    file attributes $shmpath -permissions r--r--r--
    sqlite3 db test.db
    do_test 3.7 {
      catchsql { SELECT * FROM t1 } 
    } {1 {unable to open database file}}
    
    db close
    db_restore
    file attributes $shmpath -permissions r--r--r--
    sqlite3 db test.db -readonly 1
    do_execsql_test 3.8 { SELECT * FROM t1 } {1 2}
    
    sqlite3 db2 test.db
    do_test 3.9 { db2 eval { SELECT * FROM t1 } } {1 2}
    do_test 3.10 { 
      catchsql { INSERT INTO t1 VALUES(3, 4) } db2 
    } {1 {attempt to write a readonly database}}
    
    catch { db close }
    catch { db2 close }
    
    forcedelete $shmpath
  } ;# endif capable enable_persist_wal
} ;# endif os Darwin
    
finish_test

Changes to test/walshared.test.

13
14
15
16
17
18
19

20
21
22
23
24
25
26
# "PRAGMA journal_mode=WAL" mode with shared-cache turned on.
#

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

ifcapable !wal {finish_test ; return }


db close
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]

sqlite3 db  test.db
sqlite3 db2 test.db








>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# "PRAGMA journal_mode=WAL" mode with shared-cache turned on.
#

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

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }

db close
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]

sqlite3 db  test.db
sqlite3 db2 test.db

Changes to test/walslow.test.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

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

ifcapable !wal {finish_test ; return }

set testprefix walslow

proc reopen_db {} {
  catch { db close }
  forcedelete test.db test.db-wal
  sqlite3 db test.db
  execsql { PRAGMA journal_mode = wal }







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

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

ifcapable !wal {finish_test ; return }
if ![wal_is_ok] { finish_test; return }
set testprefix walslow

proc reopen_db {} {
  catch { db close }
  forcedelete test.db test.db-wal
  sqlite3 db test.db
  execsql { PRAGMA journal_mode = wal }

Changes to test/walthread.test.

15
16
17
18
19
20
21

22
23
24
25
26
27
28

set testdir [file dirname $argv0]

source $testdir/tester.tcl
source $testdir/lock_common.tcl
if {[run_thread_tests]==0} { finish_test ; return }
ifcapable !wal             { finish_test ; return }


set sqlite_walsummary_mmap_incr 64

# How long, in seconds, to run each test for. If a test is set to run for
# 0 seconds, it is omitted entirely.
#
unset -nocomplain seconds







>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

set testdir [file dirname $argv0]

source $testdir/tester.tcl
source $testdir/lock_common.tcl
if {[run_thread_tests]==0} { finish_test ; return }
ifcapable !wal             { finish_test ; return }
if ![wal_is_ok] { finish_test; return }

set sqlite_walsummary_mmap_incr 64

# How long, in seconds, to run each test for. If a test is set to run for
# 0 seconds, it is omitted entirely.
#
unset -nocomplain seconds

Changes to test/window1.test.

1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
    FROM (SELECT (SELECT sum(a) FROM t1) AS x FROM t1);
} {12 12 12}

do_execsql_test 48.1 {
  SELECT (SELECT max(x)OVER(ORDER BY x) + min(x)OVER(ORDER BY x))
    FROM (SELECT (SELECT sum(a) FROM t1 GROUP BY a) AS x FROM t1);
} {2 2 2}


finish_test








<

1588
1589
1590
1591
1592
1593
1594
1595

1596
    FROM (SELECT (SELECT sum(a) FROM t1) AS x FROM t1);
} {12 12 12}

do_execsql_test 48.1 {
  SELECT (SELECT max(x)OVER(ORDER BY x) + min(x)OVER(ORDER BY x))
    FROM (SELECT (SELECT sum(a) FROM t1 GROUP BY a) AS x FROM t1);
} {2 2 2}


finish_test

Changes to tool/mksqlite3c.tcl.

118
119
120
121
122
123
124

125
126
127
128
129
130
131
...
393
394
395
396
397
398
399

400
401
402
403
404
405
406
   sqlite3session.h
   sqlite3.h
   sqlite3ext.h
   sqlite3rbu.h
   sqliteicu.h
   sqliteInt.h
   sqliteLimit.h

   vdbe.h
   vdbeInt.h
   vxworks.h
   wal.h
   whereInt.h
} {
  set available_hdr($hdr) 1
................................................................................
   fts3_unicode.c
   fts3_unicode2.c

   json1.c
   rtree.c
   icu.c
   fts3_icu.c

   sqlite3rbu.c
   dbstat.c
   dbpage.c
   sqlite3session.c
   fts5.c
   stmt.c
} {







>







 







>







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
   sqlite3session.h
   sqlite3.h
   sqlite3ext.h
   sqlite3rbu.h
   sqliteicu.h
   sqliteInt.h
   sqliteLimit.h
   sqlrr.h
   vdbe.h
   vdbeInt.h
   vxworks.h
   wal.h
   whereInt.h
} {
  set available_hdr($hdr) 1
................................................................................
   fts3_unicode.c
   fts3_unicode2.c

   json1.c
   rtree.c
   icu.c
   fts3_icu.c
   sqlrr.c
   sqlite3rbu.c
   dbstat.c
   dbpage.c
   sqlite3session.c
   fts5.c
   stmt.c
} {