SQLite

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 85d3dc8c to d6fda470

2020-04-16
11:35
Improve corruption detection in fts3 shadow tables earlier in order to prevent an assert() from failing. (check-in: a9ec8c8f user: dan tags: trunk)
2020-04-14
15:48
Add the UINT collating sequence extension. The implementation is copied out of the "natsort" branch. (check-in: 6f46c6e3 user: drh tags: trunk)
15:24
Merge trunk enhancements. (check-in: f1c284dd user: drh tags: natsort)
2020-04-09
18:51
Merge recent trunk changes into the apple-osx branch. (Leaf check-in: d6fda470 user: drh tags: apple-osx)
18:46
Merge recent trunk enhancements into the wal2 branch. (check-in: 6fb87062 user: drh tags: wal2)
18:44
Merge recent trunk enhancements into the begin-concurrent-pnu branch. (check-in: cedd138c user: drh tags: begin-concurrent-pnu)
18:29
Merge recent trunk enhancements into the begin-concurrent branch. (check-in: 92f71a88 user: drh tags: begin-concurrent)
15:31
When compiling the shell for WinRT, avoid using Win32 APIs that are unavailable. (check-in: 85d3dc8c user: mistachkin tags: trunk)
2020-04-07
15:07
Limit LIKE/GLOB pattern length to 100 bytes (default is 50K) when running dbsql cases in the fuzzcheck utility. (check-in: 10306118 user: drh tags: trunk)
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. (check-in: 1240ee4f user: drh tags: apple-osx)

Changes to Makefile.in.

60
61
62
63
64
65
66
67

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

67
68
69
70
71
72
73
74







-
+








# 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@
#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
#
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128







-
+







# 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@
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
349
350
351
352
353
354
355



356
357
358
359
360
361
362
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365







+
+
+







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 += \
566
567
568
569
570
571
572











573
574
575
576
577
578
579
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







+
+
+
+
+
+
+
+
+
+
+







  $(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) \
636
637
638
639
640
641
642
643
644


645
646
647
648
649
650
651
652
650
651
652
653
654
655
656


657
658

659
660
661
662
663
664
665







-
-
+
+
-







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" \
                -rpath "$(TCLLIBDIR)/sqlite3" \
		-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
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426




1427
1428
1429
1430
1431
1432
1433
1429
1430
1431
1432
1433
1434
1435




1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446







-
-
-
-
+
+
+
+







	$(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)
	$(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
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
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243







+
+
+







  $(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 += \
474
475
476
477
478
479
480


481
482
483
484
485
486
487
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492







+
+







  $(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  \
628
629
630
631
632
633
634
635

636
637
638

639
640
641
642
643
644
645
633
634
635
636
637
638
639

640
641
642

643
644
645
646
647
648
649
650







-
+


-
+








# 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
target_source:	$(SRC) $(EXTHDR) $(TOP)/tool/vdbe-compress.tcl fts5.c
	rm -rf tsrc
	mkdir tsrc
	cp -f $(SRC) 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
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
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;

/*
** 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

Changes to src/legacy.c.

12
13
14
15
16
17
18



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







+
+
+







** 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
38
39
40
41
42
43
44
45



46
47
48
49
50
51
52
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57







-
+
+
+







  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;
119
120
121
122
123
124
125



126
127
128
129
130
131
132
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140







+
+
+







    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
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28







+
+
+







** 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)
1304
1305
1306
1307
1308
1309
1310




1311
1312
1313
1314
1315
1316
1317
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324







+
+
+
+







  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
1416
1417
1418
1419
1420
1421
1422

1423
1424
1425
1426
1427
1428
1429
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437







+







      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;
2745
2746
2747
2748
2749
2750
2751






































2752
2753
2754
2755
2756
2757
2758
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
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    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
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
3033
3034
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+














-
-







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



/*
** 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(
3393
3394
3395
3396
3397
3398
3399




















3400



3401
3402
3403
3404
3405
3406
3407
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+







  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
3836
3837
3838
3839
3840
3841
3842








3843
3844
3845
3846
3847
3848
3849
3850

3851
3852
3853
3854
3855
3856
3857
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985







+
+
+
+
+
+
+
+








+







      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.
*/
4441
4442
4443
4444
4445
4446
4447


























4448
4449
4450
4451
4452
4453
4454
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    (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
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, flags & 0x1087f7f, pFlagsOut);
  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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111







+







#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
233
234
235
236
237
238
239
240

241
242



243
244
245
246
247
248
249
234
235
236
237
238
239
240

241
242
243
244
245
246
247
248
249
250
251
252
253







-
+


+
+
+







  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
#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
320
321
322
323
324
325
326




























































































































































































































































































327
328
329
330
331
332
333
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







** 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
1304
1305
1306
1307
1308
1309
1310










1311
1312

1313
1314
1315
1316
1317
1318
1319
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







+
+
+
+
+
+
+
+
+
+


+







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().
**
1525
1526
1527
1528
1529
1530
1531





1532
1533

1534
1535
1536
1537
1538
1539
1540
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845







+
+
+
+
+


+







  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);
1596
1597
1598
1599
1600
1601
1602
1603

1604
1605
1606
1607
1608
1609
1610
1901
1902
1903
1904
1905
1906
1907

1908
1909
1910
1911
1912
1913
1914
1915







-
+







** 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){
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;
1759
1760
1761
1762
1763
1764
1765
1766

1767
1768
1769

1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
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
2064
2065
2066
2067
2068
2069
2070

2071
2072
2073

2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
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







-
+


-
+


















-
+








-
+


+
+
+

+



-
+







  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) ){
    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }
  }


  /* If control gets to this point, then actually go ahead and make
  ** operating system calls for the specified lock.
  */
  if( eFileLock==SHARED_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) ){
    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) && rc==SQLITE_OK ){
    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( rc!=SQLITE_BUSY ){
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }else{
      pFile->eFileLock = SHARED_LOCK;
      pInode->nLock++;
      pInode->nShared = 1;
1827
1828
1829
1830
1831
1832
1833
1834

1835
1836
1837
1838
1839
1840
1841
2136
2137
2138
2139
2140
2141
2142

2143
2144
2145
2146
2147
2148
2149
2150







-
+







      lock.l_start = RESERVED_BYTE;
      lock.l_len = 1L;
    }else{
      lock.l_start = SHARED_FIRST;
      lock.l_len = SHARED_SIZE;
    }

    if( unixFileLock(pFile, &lock) ){
    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
        storeLastErrno(pFile, tErrno);
      }
    }
  }
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
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







-
+

+
+
+

+







-
+

+

+
+
+









-
+

+
+
+

+
+
+
+










-
+
+
+
+
+







-
+
+
+
+
+








-
+


+
+
+
+
+
+
+


+













-
+


+
+
+
+
+
+
+


+







        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) ){
        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)==(-1) ){
        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)==(-1) ){
        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) ){
        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, errno);
          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)==0 ){
    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)==0 ){
      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
2182
2183
2184
2185
2186
2187
2188















2189



2190
2191
2192
2193
2194
2195
2196
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+







  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);
  }
  return closeUnixFile(id);
  rc = closeUnixFile(id);
  unixLeaveMutex();
  return rc;
}

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

/******************************************************************************
************************* Begin dot-file Locking ******************************
2348
2349
2350
2351
2352
2353
2354



2355

2356
2357
2358
2359
2360
2361
2362
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731







+
+
+

+







  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;
}
2430
2431
2432
2433
2434
2435
2436



2437





2438
2439
2440
2441
2442
2443
2444
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821







+
+
+

+
+
+
+
+







    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 */
3547
3548
3549
3550
3551
3552
3553






3554
3555
3556
3557
3558
3559
3560
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943







+
+
+
+
+
+







*/
#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
3611
3612
3613
3614
3615
3616
3617








3618

3619
3620
3621
3622
3623
3624
3625
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017







+
+
+
+
+
+
+
+

+







#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 
3742
3743
3744
3745
3746
3747
3748






3749

3750
3751
3752
3753
3754

3755
3756
3757
3758
3759
3760
3761
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







+
+
+
+
+
+

+





+







  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
*/
3849
3850
3851
3852
3853
3854
3855

3856
3857
3858
3859
3860
3861
3862
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263







+







*/
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
3905
3906
3907
3908
3909
3910
3911














































































































































































































































































































3912
3913
3914
3915
3916
3917
3918
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    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.
*/
4040
4041
4042
4043
4044
4045
4046




















4047
4048
4049
4050
4051
4052
4053
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
4775
4776







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#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 
4470
4471
4472
4473
4474
4475
4476




4477
4478
4479
4480
4481
4482
4483
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210







+
+
+
+







  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
4537
4538
4539
4540
4541
4542
4543

4544
4545
4546
4547














4548
4549
4550
4551
4552
4553
4554
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
5295
5296







+




+
+
+
+
+
+
+
+
+
+
+
+
+
+







#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 ){
4573
4574
4575
4576
4577
4578
4579







4580
4581
4582
4583
4584
4585
4586
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335







+
+
+
+
+
+
+







      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));
4974
4975
4976
4977
4978
4979
4980
4981
4982






4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
























































































































































































































































































































































































































4999
5000
5001
5002
5003
5004
5005
5723
5724
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
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166







-
-
+
+
+
+
+
+
















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  /* 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);
    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 ){
5370
5371
5372
5373
5374
5375
5376
5377

5378
5379
5380
5381
5382
5383
5384
6531
6532
6533
6534
6535
6536
6537

6538
6539
6540
6541
6542
6543
6544
6545







-
+







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 */
  2,                        /* shared memory is enabled */
  proxyClose,               /* xClose method */
  proxyLock,                /* xLock method */
  proxyUnlock,              /* xUnlock method */
  proxyCheckReservedLock,   /* xCheckReservedLock method */
  0                         /* xShmMap method */
)
#endif
5567
5568
5569
5570
5571
5572
5573


5574
5575
5576
5577
5578
5579
5580
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743







+
+







#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:
5947
5948
5949
5950
5951
5952
5953

5954




5955
5956
5957
5958
5959
5960
5961
7110
7111
7112
7113
7114
7115
7116
7117

7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128







+
-
+
+
+
+







  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&0x0FFF00;  /* Type of file to open */
  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);
6059
6060
6061
6062
6063
6064
6065




6066
6067
6068
6069
6070
6071
6072
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243







+
+
+
+







  ** '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 );
6133
6134
6135
6136
6137
6138
6139
6140

6141
6142
6143
6144
6145
6146
6147
7304
7305
7306
7307
7308
7309
7310

7311
7312
7313
7314
7315
7316
7317
7318







-
+







      robust_close(p, fd, __LINE__);
      return SQLITE_NOMEM_BKPT;
    }
#else
    osUnlink(zName);
#endif
  }
#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  else{
    p->openFlags = openFlags;
  }
#endif
  
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
  if( fstatfs(fd, &fsInfo) == -1 ){
6160
6161
6162
6163
6164
6165
6166





6167
6168
6169
6170
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
7331
7332
7333
7334
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
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372

7373
7374
7375
7376
7377
7378
7379
7380
7381







+
+
+
+
+



















+
+






+
+
+
-
+
+







  /* 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");
    int useProxy = 0;

    /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means 
    ** never use proxy, NULL means use proxy for non-local files only.  */
    if( envforce!=NULL ){
      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);
            unixClose(pFile);
          }
          return rc;
        }
      }
      goto open_finished;
    }
  }
#endif
6239
6240
6241
6242
6243
6244
6245





6246

6247
6248
6249
6250
6251
6252
6253
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441







+
+
+
+
+

+







  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;
6870
6871
6872
6873
6874
6875
6876


























6877
6878
6879
6880
6881
6882
6883
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
8078
8079
8080
8081
8082
8083
8084
8085
8086
8087
8088
8089
8090
8091
8092
8093
8094
8095
8096
8097







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    }
    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.
*/
6920
6921
6922
6923
6924
6925
6926

6927
6928
6929
6930
6931
6932
6933
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145
8146
8147
8148







+







  }
  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: 
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
7136
7137
7138


7139
7140
7141
7142
7143
7144
7145
7146
7147
7148

7149
7150
7151
7152
7153
7154
7155
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
8366


8367
8368
8369
8370
8371
8372
8373
8374
8375
8376
8377

8378
8379
8380
8381
8382
8383
8384
8385







-





-

+












-
+





-
+





-
+







-
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+










-
-
+
+









-
+







/* 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 ){
      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( nTries==1 ){
      if( pCtx->nFails==1 ){
        conchModTime = buf.st_mtimespec;
        usleep(500000); /* wait 0.5 sec and try the lock again*/
        continue;  
      }

      assert( nTries>1 );
      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( nTries==2 ){  
      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 */
          /* 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( nTries==3 );
      if( 0==proxyBreakConchLock(pFile, myHostID) ){
      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 && nTries<3 );
  } 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 
7317
7318
7319
7320
7321
7322
7323






7324

7325
7326
7327
7328
7329
7330
7331
8547
8548
8549
8550
8551
8552
8553
8554
8555
8556
8557
8558
8559
8560
8561
8562
8563
8564
8565
8566
8567
8568







+
+
+
+
+
+

+







      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{
7560
7561
7562
7563
7564
7565
7566



7567
7568
7569
7570
7571
7572
7573
8797
8798
8799
8800
8801
8802
8803
8804
8805
8806
8807
8808
8809
8810
8811
8812
8813







+
+
+







        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;
    }
7599
7600
7601
7602
7603
7604
7605
7606

7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622

7623
7624
7625
7626
7627
7628
7629
8839
8840
8841
8842
8843
8844
8845

8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
8859
8860
8861

8862
8863
8864
8865
8866
8867
8868
8869







-
+















-
+







** 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 ){
      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)";
        }
      } else {
        *(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);
      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
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.

2497
2498
2499
2500
2501
2502
2503




2504

2505
2506
2507
2508
2509
2510
2511
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507

2508
2509
2510
2511
2512
2513
2514
2515







+
+
+
+
-
+







  ** 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
    const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
      (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
2534
2535
2536
2537
2538
2539
2540




2541

2542
2543
2544
2545
2546
2547
2548
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548

2549
2550
2551
2552
2553
2554
2555
2556







+
+
+
+
-
+







    }
    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
      int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
        (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);
3605
3606
3607
3608
3609
3610
3611




3612

3613
3614
3615
3616
3617
3618
3619
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623

3624
3625
3626
3627
3628
3629
3630
3631







+
+
+
+
-
+







){
  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
  vfsFlags |=  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
            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;
}

/*
5089
5090
5091
5092
5093
5094
5095




5096

5097
5098
5099
5100
5101
5102
5103
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111

5112
5113
5114
5115
5116
5117
5118
5119







+
+
+
+
-
+







          /* 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
            int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
              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;
5229
5230
5231
5232
5233
5234
5235




5236

5237
5238
5239
5240
5241
5242
5243
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255

5256
5257
5258
5259
5260
5261
5262
5263







+
+
+
+
-
+







      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
          int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
            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);
          }
5736
5737
5738
5739
5740
5741
5742



5743
5744
5745
5746
5747
5748
5749
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772







+
+
+







    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);
        }
6974
6975
6976
6977
6978
6979
6980












6981
6982
6983
6984
6985
6986
6987
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022







+
+
+
+
+
+
+
+
+
+
+
+







** 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;
7460
7461
7462
7463
7464
7465
7466

7467
7468
7469






7470

7471
7472
7473
7474
7475
7476
7477
7495
7496
7497
7498
7499
7500
7501
7502



7503
7504
7505
7506
7507
7508

7509
7510
7511
7512
7513
7514
7515
7516







+
-
-
-
+
+
+
+
+
+
-
+







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


7557
7558
7559
7560
7561
7562
7563







7564
7565
7566
7567
7568
7569
7570
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616







+
+
+
+
+
+
+







  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.

199
200
201
202
203
204
205

206
207
208
209
210
211
212
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213







+







#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
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 = 0;
      nFreed = sqlite3MallocSize(p);
      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
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 & PAGER_SYNCHRONOUS_MASK)
                 pDb->safety_level | (db->flags & PAGER_FLAGS_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
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26







+
+
+







**
*************************************************************************
** 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 */
774
775
776
777
778
779
780



781
782
783
784
785
786
787
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793







+
+
+







  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. */
814
815
816
817
818
819
820



821
822
823
824
825
826
827
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836







+
+
+







  ** 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
/*
857
858
859
860
861
862
863
864



865
866
867
868
869
870
871
866
867
868
869
870
871
872

873
874
875
876
877
878
879
880
881
882







-
+
+
+







    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
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.

342
343
344
345
346
347
348
















349
350
351
352
353
354
355
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#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
4918
4919
4920
4921
4922
4923
4924
























4925
4926
4927
4928
4929
4930
4931
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







# 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.

4046
4047
4048
4049
4050
4051
4052


















4053
4054
4055
4056
4057
4058
4059
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    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,
5891
5892
5893
5894
5895
5896
5897


























































































5898
5899
5900
5901
5902
5903
5904
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  }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.
*/
6035
6036
6037
6038
6039
6040
6041




















































































6042
6043
6044
6045
6046
6047
6048
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







      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.
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6361
6362
6363
6364
6365
6366
6367

6368
6369
6370
6371
6372
6373
6374







-







  }
  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(
7940
7941
7942
7943
7944
7945
7946

7947
7948
7949
7950
7951
7952
7953
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145







+







     { "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 },
8055
8056
8057
8058
8059
8060
8061




8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075


8076
8077
8078
8079
8080
8081
8082
8247
8248
8249
8250
8251
8252
8253
8254
8255
8256
8257
8258
8259
8260
8261
8262
8263
8264
8265
8266
8267
8268
8269
8270
8271
8272
8273
8274
8275
8276
8277
8278
8279
8280







+
+
+
+














+
+







     { "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.

606
607
608
609
610
611
612
613















614
615
616
617
618
619
620
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







-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  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

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
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#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
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158







-
+







}

/*
** 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){
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 ){
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
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







-
+


+














-
+







**
** 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(
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, zVfs
    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
334
335
336
337
338
339
340
341

342
343
344
345
346
347
348
335
336
337
338
339
340
341

342
343
344
345
346
347
348
349







-
+







  }
  if( objc>4 ){
    busy.interp = interp;
    busy.pScript = objv[4];
    xBusy = superlock_busy;
  }

  rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock);
  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
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 );
  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( AtomicLoad(&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
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27







+
+
+







*************************************************************************
**
** 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
100
101
102
103
104
105
106



107
108
109
110
111
112
113
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119







+
+
+







  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);
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
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







+
+
+



















+
+
+
+
+
+
+
-
+







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);
  }
  return rc;
}

/*
** 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
  sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->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 );
1410
1411
1412
1413
1414
1415
1416



1417
1418
1419
1420
1421
1422
1423
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442







+
+
+







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, 
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
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







+
+
+








+
+
+





+
+
+










+
+
+







  }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(
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







+
+
+







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, 
1512
1513
1514
1515
1516
1517
1518



1519
1520
1521
1522
1523
1524
1525
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562







+
+
+







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: {
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
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







+
+
+














+
+
+







        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.

1330
1331
1332
1333
1334
1335
1336

1337
1338
1339
1340
1341

1342
1343
1344
1345
1346
1347
1348
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341

1342
1343
1344
1345
1346
1347
1348
1349







+




-
+







*/
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 flags;                      /* Flags passed to OsOpen() */
  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.
1373
1374
1375
1376
1377
1378
1379



1380
1381
1382




1383
1384
1385
1386
1387
1388
1389
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383



1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394







+
+
+
-
-
-
+
+
+
+







  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 {
  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 ){
    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);
2085
2086
2087
2088
2089
2090
2091



2092
2093
2094
2095
2096
2097
2098
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106







+
+
+







  **
  ** 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 */
  }  
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3008
3009
3010
3011
3012
3013
3014

3015
3016
3017
3018
3019
3020
3021







-







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
3218
3219
3220
3221
3222
3223
3224




3225
3226
3227
3228
3229
3230
3231
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242







+
+
+
+







*/
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,
3261
3262
3263
3264
3265
3266
3267



3268


3269

3270





3271
3272
3273
3274

3275
3276
3277
3278
3279
3280
3281
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304







+
+
+

+
+

+

+
+
+
+
+




+







  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
  
  pData = pPage->pData;

  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
3426
3427
3428
3429
3430
3431
3432







3433
3434
3435
3436
3437
3438
3439
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469







+
+
+
+
+
+
+







  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
3457
3458
3459
3460
3461
3462
3463
3464






3465
3466
3467
3468
3469
3470
3471
3487
3488
3489
3490
3491
3492
3493

3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506







-
+
+
+
+
+
+







      }
    }

    iFrame++;
    assert( iOffset==walFrameOffset(iFrame, szPage) );
    nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
    rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
    if( rc ) return rc;
    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 ){
3492
3493
3494
3495
3496
3497
3498
3499






3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510



3511
3512
3513
3514
3515
3516
3517
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
3556
3557
3558
3559
3560







-
+
+
+
+
+
+











+
+
+







    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;
        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
51
52
53
54
55
56
57

58
59
60
61
62
63
64
65







-
+








/* 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 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
74
75
76
77
78
79
80



81
82
83
84
85
86
87
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90







+
+
+







/* 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
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
561
562
563
564
565
566
567
568
569
570
571
572




573
574
575
576
577
578
579
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







-
+



















+
+
+
+







    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 {
  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
  do_catchsql_test 16.23 {
    CREATE TABLE y1_segments AS SELECT * FROM abc;
  } {1 {object name reserved for internal use: y1_segments}}
  do_catchsql_test 16.24 {
    CREATE VIEW y1_segments AS SELECT * FROM abc;
  } {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.

756
757
758
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
756
757
758
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







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#
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}
  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
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
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
123
124
125
126
127
128
129
130
131
132


133


134
135
136


137


138
139
140
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







+
+
-
-
+
+



+
+
-
+
+

















+
+
-
+
+



+
+
-
+
+



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_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
  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);
    PRAGMA lock_status;
} {main reserved temp closed}
do_test cache-2.4.2 { pager_cache_size db } 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_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
  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
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
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
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
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 using_proxy 0
foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
  set using_proxy $value
}
set extrafds 0
if {$using_proxy!=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
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_chunksize_test db main [expr 32*1024]
  
    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
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
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
  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
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







# 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
}
129
130
131
132
133
134
135


136
137
138
139
140
141
142
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145







+
+







    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
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
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"
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
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);
  }
} {}
  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}
  # 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.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.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.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.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.7 {
    db close
    catchsql { SELECT * FROM t1 } db2
  } {0 {1 2}}

do_test lock5-flock.8 {
  db2 close
} {}
  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
  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 {
      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
  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}

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

do_test lock5-none.X {
  db close
  db2 close
} {}
  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
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







+

+

-








-
+












+

+

-







    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 {
      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}
  } $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 {
      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

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
310
311
312
313
314
315
316

317
318
319
320
321
322
323
324

325
326
327
328
329
330
331
332







-
+







-
+







  } {0 {}}
}

# Here are some tests for tokenize.c.  
#
do_test main-3.1 {
  catch {db close}
  foreach f [glob -nocomplain testdb/*] {forcedelete $f}
  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}
  foreach f [glob -nocomplain testdb/*] {forcedelete $f}
  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}
438
439
440
441
442
443
444
445

446
447
448
449
450
451
452
438
439
440
441
442
443
444

445
446
447
448
449
450
451
452







-
+







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}
  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
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}
      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
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 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} {
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20













-







# 2001 September 15
#
# 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 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 {

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
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







+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





    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 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
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







+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+







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

172
173
174




175
176
177
178
179
180
181
167
168
169
170
171
172
173
174



175
176
177
178
179
180
181
182
183
184
185







+
-
-
-
+
+
+
+







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.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
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
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564







+
+







    }
    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
735
736
737
738
739
740
741

742
743
744
745
746
747
748
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751







+







  }

  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
1216
1217
1218
1219
1220
1221
1222
1223

1224
1225
1226
1227
1228
1229
1230
1219
1220
1221
1222
1223
1224
1225

1226
1227
1228
1229
1230
1231
1232
1233







-
+







#   $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 {
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;
1252
1253
1254
1255
1256
1257
1258



1259
1260
1261
1262
1263
1264
1265
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271







+
+
+







    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]
  }
}

2044
2045
2046
2047
2048
2049
2050
2051

2052
2053
2054
2055
2056
2057
2058
2050
2051
2052
2053
2054
2055
2056

2057
2058
2059
2060
2061
2062
2063
2064







-
+







do_test pager1-20.2.2 {
  execsql {
    BEGIN EXCLUSIVE;
    COMMIT;
  }
} {}

ifcapable wal {
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;
2079
2080
2081
2082
2083
2084
2085
2086

2087
2088
2089
2090
2091
2092
2093
2085
2086
2087
2088
2089
2090
2091

2092
2093
2094
2095
2096
2097
2098
2099







-
+








#-------------------------------------------------------------------------
# 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 {
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;
    }
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
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







-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
-
-
-








#-------------------------------------------------------------------------
# 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}
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;
  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;
      PRAGMA journal_mode = WAL;
      INSERT INTO ko DEFAULT VALUES;
    }
    INSERT INTO ko DEFAULT VALUES;
    PRAGMA wal_checkpoint;
  }
    execsql { PRAGMA wal_checkpoint }
    set synccount
  } {0}
  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.
#
2384
2385
2386
2387
2388
2389
2390
2391

2392
2393
2394
2395
2396
2397
2398
2393
2394
2395
2396
2397
2398
2399

2400
2401
2402
2403
2404
2405
2406
2407







-
+








#-------------------------------------------------------------------------
# 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 {
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
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
113
114
115
116
117
118
119

120
121
122
123
124
125
126
127
128
129







-
+
+
+







  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
174
175
176
177
178
179
180


181


182
176
177
178
179
180
181
182
183
184

185
186
187







+
+
-
+
+

    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
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 {
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="mylittleproxy";
      select * from sqlite_master;
    execsql "PRAGMA lock_proxy_file='$lpp'"
    execsql "select * from sqlite_master"
    }
    execsql {
      PRAGMA lock_proxy_file;
    } 
    execsql "PRAGMA lock_proxy_file"
  } $lpp
  } {mylittleproxy}

  # 2 database connections can share a lock proxy file
  do_test pragma-16.2 {
    sqlite3 db2 test.db
    execsql {
      PRAGMA lock_proxy_file="mylittleproxy";
    execsql "PRAGMA lock_proxy_file='$lpp'" db2
    } 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
    execsql "PRAGMA lock_proxy_file" db2
  } $lpp
  } {mylittleproxy}

  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="myotherproxy";
    execsql "PRAGMA lock_proxy_file='$lpp2'" db2
    } 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="myoriginalproxy";
      PRAGMA lock_proxy_file="myotherproxy";
      PRAGMA lock_proxy_file;
    } db2
    execsql "PRAGMA lock_proxy_file='$lpp3'" db2
    execsql "PRAGMA lock_proxy_file='$lpp2'" db2
    execsql "PRAGMA lock_proxy_file" db2
  } $lpp2
  } {myotherproxy}

  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
  } {myotherproxy}
  } $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="yetanotherproxy";
      PRAGMA lock_proxy_file;
    } 
    execsql "PRAGMA lock_proxy_file='$lpp4'" 
    execsql "select * from sqlite_master"
    execsql "PRAGMA lock_proxy_file"
  } $lpp4
  
  } {yetanotherproxy}
  do_test pragma-16.8.2 {
    execsql {
      create table mine(x);
      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
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33







-
+







  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.
# 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"
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
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







+
+








-
+














-
+







 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 1.$tn.1 $sql 0
  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.

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
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













+
+
+
+





+
+








# 2015-05-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 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
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 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} {
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
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
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} {
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
  }] $expected]
  }] [ expr $expected+$extrafds ] ]
}

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.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
} 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
} 2 $extrafds

finish_test

Changes to test/superlock.test.

9
10
11
12
13
14
15

16
17
18
19
20
21
22
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23







+







#
#***********************************************************************
#

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
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
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







+
+
+
+
+















+
+
+
+
+
+







#        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}

ifcapable !wal {
  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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70







+
+
+
+
+







# 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.
  #
77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
93
94
95
96

97
98
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100

101
102
103







-
+











-
+


      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)]
} [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 + (0==$jrnl_in_memory)]
} [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
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








+
+
+
+
+
+
+
+








# 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
1310
1311
1312
1313
1314
1315
1316

1317
1318
1319
1320
1321








1322
1323
1324
1325
1326
1327
1328
1335
1336
1337
1338
1339
1340
1341
1342





1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357







+
-
-
-
-
-
+
+
+
+
+
+
+
+







      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
  }
  foreach f [glob -nocomplain test.db-mj*] {
    forcedelete $f
    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]
2225
2226
2227
2228
2229
2230
2231













2232
2233
2234
2235
2236
2237
2238
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280







+
+
+
+
+
+
+
+
+
+
+
+
+







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

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.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}}
  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
}

Changes to test/wal.test.

18
19
20
21
22
23
24




25
26
27
28
29
30
31
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35







+
+
+
+







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
}
169
170
171
172
173
174
175



176
177
178
179
180
181
182
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189







+
+
+







  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 }
220
221
222
223
224
225
226



227
228
229
230
231
232
233
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243







+
+
+







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
334
335
336
337
338
339
340



341
342
343
344
345
346
347
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360







+
+
+








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);
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
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







+
+
+














+
+
+







  }
} {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;
  }
781
782
783
784
785
786
787



788
789
790
791
792
793
794
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816







+
+
+







    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]
818
819
820
821
822
823
824



825
826
827
828
829
830
831
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856







+
+
+







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
975
976
977
978
979
980
981

982
983

984
985

986
987
988
989
990
991
992
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011

1012
1013
1014
1015
1016
1017
1018
1019







+


+

-
+







    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}
  } {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));
1049
1050
1051
1052
1053
1054
1055

1056
1057
1058
1059
1060
1061
1062
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090







+








  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} {
1264
1265
1266
1267
1268
1269
1270



1271
1272
1273
1274
1275
1276
1277
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308







+
+
+







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
1418
1419
1420
1421
1422
1423
1424



1425
1426
1427
1428
1429
1430
1431
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465







+
+
+







  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 }
1464
1465
1466
1467
1468
1469
1470



1471
1472
1473
1474
1475
1476
1477
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514







+
+
+







    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
1492
1493
1494
1495
1496
1497
1498



1499
1500
1501
1502
1503
1504
1505
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545







+
+
+







  # 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
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32







+







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
  } {
66
67
68
69
70
71
72







73
74
75
76
77
78
79
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87







+
+
+
+
+
+
+







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.
569
570
571
572
573
574
575



576
577
578



579
580
581
582
583
584
585
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599







+
+
+



+
+
+







      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');
726
727
728
729
730
731
732


733

734
735
736
737
738
739
740
740
741
742
743
744
745
746
747
748

749
750
751
752
753
754
755
756







+
+
-
+







    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;
957
958
959
960
961
962
963



964
965
966
967
968
969
970
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989







+
+
+







  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 {
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
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







+
+
+
+
+













-
+














-
+




-
+


-
+



+
+
+

-
+












-
+









+
+
+
+








-
+

+
+
+













+
+
+



-
+



-
+














+
+
+
+








#-------------------------------------------------------------------------
# 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 test.db-shm]
    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 test.db-shm]
      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 test.db-shm]
      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 test.db-shm -perm]]
      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 test.db-shm]
      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 test.db-shm} {
    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 test.db-shm] [file exists test.db-wal]
    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 test.db-shm -perm $shm_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 test.db-shm -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}}
1214
1215
1216
1217
1218
1219
1220


1221
1222
1223
1224
1225
1226
1227
1228
1229
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
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
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







+
+
















-
+







-
+











-
+







  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;
      INSERT INTO t1 VALUES(3, 4);
      INSERT INTO t1 VALUES(5, 6);
    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]
  } [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 $reslist 2 3]
  } [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 $reslist 4 5]
  } [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
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
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
}
207
208
209
210
211
212
213


214
215
216
217
218
219
220
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223







+
+







    {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
229
230
231
232
233
234
235
236

237
238
239
240
241
242
243
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246







-
+







    execsql {
      CREATE TABLE x(y);
      INSERT INTO x VALUES('z');
      PRAGMA wal_checkpoint;
    }
    T filter {}
    set ::syncs
  } $synccount
  } $usecount

  db close
  T delete
}


#-------------------------------------------------------------------------

Changes to test/wal4.test.

12
13
14
15
16
17
18




19
20
21
22
23
24
25
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
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/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 }

76
77
78
79
80
81
82





83
84
85
86
87
88
89
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95







+
+
+
+
+







    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}
339
340
341
342
343
344
345





346
347
348
349
350
351
352
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363







+
+
+
+
+








    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
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
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
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
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
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31







+







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.
320
321
322
323
324
325
326



327
328
329
330
331
332
333
334



335
336
337
338
339
340
341
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







+
+
+








+
+
+







  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
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
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
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
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
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
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
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32







+







#

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
67
68
69
70
71
72
73



74
75



76
77
78
79
80
81
82
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89







+
+
+


+
+
+







    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
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
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+










-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-

















+
+
+
















+
+
+







  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}

if {[atomic_batch_write test.db]==0} {
  set expected_sync_count 3
  if {$::tcl_platform(platform)!="windows"} {
    ifcapable dirsync {
      incr expected_sync_count
# 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 {
  file exists test.db-wal
} {0}
do_test walmode-1.5 {
  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.
#
do_test walmode-2.1 {
  sqlite3 db test.db
  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 
102
103
104
105
106
107
108



109
110
111
112
113
114
115
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144







+
+
+







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







+
+
+

















+
+
+








# 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 2}
do_test walmode-4.9 {
  catchsql { PRAGMA journal_mode = delete } db
} {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]
299
300
301
302
303
304
305



306
307
308
309
310
311
312
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350







+
+
+







# 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
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27







+







# 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

#--------------------------------------------------------------------------
49
50
51
52
53
54
55



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







+
+
+







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
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
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







+
+
+
+
+
+










-
+

+
-
-
-
-
+
+
+
+
+
+
+
+
+
+





-
+

+
-
-
-
+
+
+
+
+
+
+
+

















-
+







-
+







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 test.db-shm
  file exists $shmpath
} {1}
ifcapable enable_persist_wal {
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.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 test.db-shm]
  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 {
  file_control_persist_wal db -1
} {0 0}
  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 0
} {0 0}
do_test walpersist-1.9 {
  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]
  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 test.db-shm test.db-wal
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);
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
112
113
114
115
116
117
118

119
120
121
122
123
124
125
126







-
+







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
  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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47







+
+
+
+
+
+
+
+








# 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 }
58
59
60
61
62
63
64
65

66
67
68
69

70
71
72
73
74
75
76
66
67
68
69
70
71
72

73
74
75
76

77
78
79
80
81
82
83
84







-
+



-
+







    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
    file exists $shmpath
  } {1}

  do_test 1.1.2 {
    file attributes test.db-shm -permissions r--r--r--
    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}

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
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







-
+









-
-
-
+
+
+








-
+



-
+







  } {}
  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]
    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 test.db-shm -permissions rw-r--r--
    hexio_write test.db-shm 0 01020304 
    file attributes test.db-shm -permissions r--r--r--
    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 test.db-shm -permissions rw-r--r--
    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 test.db-shm -permissions r--r--r--
  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');
    }
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
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







+
+
+
+


-
+







-
-
+
+







    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 test.db-shm
    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 test.db-shm w]
    file attributes test.db-shm -permissions r--r--r--
    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}

293
294
295
296
297
298
299

































































300
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


  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
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
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
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
1598
1599
1600
1601
1602
1588
1589
1590
1591
1592
1593
1594

1595
1596
1597
1598
1599
1600
1601







-







    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}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 49.1 {
  CREATE TABLE t1 (a PRIMARY KEY);
  INSERT INTO t1 VALUES(1);
}

Changes to tool/mksqlite3c.tcl.

118
119
120
121
122
123
124

125
126
127
128
129
130
131
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132







+







   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
393
394
395
396
397
398
399

400
401
402
403
404
405
406
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408







+







   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
} {