/ Changes On Branch reuse-schema
Login

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

Changes In Branch reuse-schema Excluding Merge-Ins

This is equivalent to a diff from 5bbd4bddd3 to b1a77b7ead

2020-08-11
16:46
Remove an unused #define from sqliteInt.h. (check-in: d5b254f94c user: drh tags: trunk)
14:55
Merge all changes since the 3.32.0 release into the reuse-schema branch. (Leaf check-in: b1a77b7ead user: drh tags: reuse-schema)
11:34
Merge latest trunk changes into this branch. (Leaf check-in: 91262e6657 user: dan tags: wal2)
2020-08-10
21:30
Merge recent trunk fixes into the begin-concurrent-pnu branch. (Leaf check-in: 2ae78c993e user: drh tags: begin-concurrent-pnu)
21:16
Merge recent trunk enhancements into begin-concurrent. (Leaf check-in: ed4c742c4e user: drh tags: begin-concurrent)
21:01
Simplify #ifdefs associated with Parse.eParseMode. Fix an #ifdef error associated with SQLITE_OMIT_AUTOVACUUM. (check-in: 5bbd4bddd3 user: drh tags: trunk)
19:35
Fix a problem causing test failures in corruptL.test for some permutations. (check-in: 680bdc6524 user: dan tags: trunk)
2020-05-25
16:34
Update the reuse-schema branch to version 3.32.1 (check-in: ecf8dece03 user: drh tags: reuse-schema)

Changes to Makefile.in.

414
415
416
417
418
419
420

421
422
423
424
425
426
427
...
471
472
473
474
475
476
477

478
479
480
481
482
483
484
  $(TOP)/src/test_mutex.c \
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_quota.c \
  $(TOP)/src/test_rtree.c \
  $(TOP)/src/test_schema.c \

  $(TOP)/src/test_server.c \
  $(TOP)/src/test_superlock.c \
  $(TOP)/src/test_syscall.c \
  $(TOP)/src/test_tclsh.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/test_thread.c \
  $(TOP)/src/test_vdbecov.c \
................................................................................
#
TESTSRC2 = \
  $(TOP)/src/attach.c \
  $(TOP)/src/backup.c \
  $(TOP)/src/bitvec.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/build.c \

  $(TOP)/src/ctime.c \
  $(TOP)/src/date.c \
  $(TOP)/src/dbpage.c \
  $(TOP)/src/dbstat.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/func.c \
  $(TOP)/src/global.c \







>







 







>







414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  $(TOP)/src/test_mutex.c \
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_quota.c \
  $(TOP)/src/test_rtree.c \
  $(TOP)/src/test_schema.c \
  $(TOP)/src/test_schemapool.c \
  $(TOP)/src/test_server.c \
  $(TOP)/src/test_superlock.c \
  $(TOP)/src/test_syscall.c \
  $(TOP)/src/test_tclsh.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/test_thread.c \
  $(TOP)/src/test_vdbecov.c \
................................................................................
#
TESTSRC2 = \
  $(TOP)/src/attach.c \
  $(TOP)/src/backup.c \
  $(TOP)/src/bitvec.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/build.c \
  $(TOP)/src/callback.c \
  $(TOP)/src/ctime.c \
  $(TOP)/src/date.c \
  $(TOP)/src/dbpage.c \
  $(TOP)/src/dbstat.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/func.c \
  $(TOP)/src/global.c \

Changes to Makefile.msc.

1531
1532
1533
1534
1535
1536
1537

1538
1539
1540
1541
1542
1543
1544
  $(TOP)\src\test_mutex.c \
  $(TOP)\src\test_onefile.c \
  $(TOP)\src\test_osinst.c \
  $(TOP)\src\test_pcache.c \
  $(TOP)\src\test_quota.c \
  $(TOP)\src\test_rtree.c \
  $(TOP)\src\test_schema.c \

  $(TOP)\src\test_server.c \
  $(TOP)\src\test_superlock.c \
  $(TOP)\src\test_syscall.c \
  $(TOP)\src\test_tclsh.c \
  $(TOP)\src\test_tclvar.c \
  $(TOP)\src\test_thread.c \
  $(TOP)\src\test_vdbecov.c \







>







1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
  $(TOP)\src\test_mutex.c \
  $(TOP)\src\test_onefile.c \
  $(TOP)\src\test_osinst.c \
  $(TOP)\src\test_pcache.c \
  $(TOP)\src\test_quota.c \
  $(TOP)\src\test_rtree.c \
  $(TOP)\src\test_schema.c \
  $(TOP)\src\test_schemapool.c \
  $(TOP)\src\test_server.c \
  $(TOP)\src\test_superlock.c \
  $(TOP)\src\test_syscall.c \
  $(TOP)\src\test_tclsh.c \
  $(TOP)\src\test_tclvar.c \
  $(TOP)\src\test_thread.c \
  $(TOP)\src\test_vdbecov.c \

Added doc/shared_schema.md.





























































































































































































































































































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

Shared-Schema Mode Notes
========================

The [reuse-schema](/timeline?r=reuse-schema) branch contains changes 
to allow SQLite connections to share schemas
between database connections within the same process in order to save memory.
Schemas may be shared between multiple databases attached to the same or
distinct connection handles.

Compile with -DSQLITE\_ENABLE\_SHARED\_SCHEMA in order to enable the
shared-schema enhancement.  Enabling the shared-schema enhancement causes
approximately a 0.1% increase in CPU cycles consumed and about a 3000-byte
increase in the size of the library, even if shared-schema is never used.

Assuming the compile-time requirements are satisfied, the shared-schema
feature is engaged by opening the database connection using the
sqlite3_open_v2() API with the SQLITE_OPEN_SHARED_SCHEMA
flag specified.  The main database and any attached databases will then share
an in-memory Schema object with any other database opened within the process
for which: 

  * the contents of the sqlite_master table, including all object names,
    SQL statements and root pages are identical, and
  * have the same values for the schema-cookie.

Temp databases (those populated with "CREATE TEMP TABLE" and similar
statements) never share schemas.

Connections opened with the SQLITE_OPEN_SHARED_SCHEMA flag
specified may not modify any database schema except that belonging to the
temp database in anyway. This includes creating or dropping database 
objects, vacuuming the database, or running ANALYZE when the
sqlite_stat\[14\] tables do not exist.

For SQLITE_OPEN_SHARED_SCHEMA connections, the
SQLITE_DBSTATUS_SCHEMA_USED sqlite3_db_status() verb
distributes the memory used for a shared schema object evenly between all
database connections that share it.

## The ".shared-schema" Command

The shell tool on this branch contains a special dot-command to help with
managing databases. The ".shared-schema" dot-command can be used to test
whether or not two databases are similar enough to share in-memory schemas,
and to fix minor problems that prevent them from doing so. To test if
two or more database are compatible, one database is opened directly using 
the shell tool and the following command issued:

        .shared-schema check <database-1> [<database-2>]...

where &lt;database-1&gt; etc. are replaced with the names of database files
on disk. For each database specified on the command line, a single line of
output is produced. If the database can share an in-memory schema with the
main database opened by the shell tool, the output is of the form:

        <database> is compatible

Otherwise, if the database cannot share a schema with the main db, the output
is of the form:

        <database> is NOT compatible (<reason>)

where &lt;reason&gt; indicates the cause of the incompatibility. &lt;reason&gt;
is always one of the following.

<ul>
  <li> <b>objects</b> - the databases contain a different set schema objects
  (tables, indexes, views and triggers).

  <li> <b>SQL</b> - the databases contain the same set of objects, but the SQL
  statements used to create them were not the same.

  <li> <b>root pages</b> - the databases contain the same set of objects created
  by the same SQL statements, but the root pages are not the same.

  <li> <b>order of sqlite&#95;master rows</b> - the databases contain the same
  set of objects created by the same SQL statements with the same root pages,
  but the order of the rows in the sqlite&#95;master tables are different.

  <li> <b>schema cookie</b> - the database schemas are compatible, but the 
  schema cookie values ("PRAGMA schema&#95;version") are different.
</ul>

The final three problems in the list above can be fixed using the
.shared-schema command. To modify such a database so that it can share a 
schema with the main database, the following shell command is used:

        .shared-schema fix <database-1> [<database-2>]...

If a database can be modified so that it may share a schema with the main
database opened by the shell tool, output is as follows:

        Fixing <database>... <database> is compatible

If a database does not require modification, or cannot be modified such that
it can share a schema with the main database, the output of "fix" is identical
to that of the "check" command.

## Implementation Notes

A single Schema object is never used by more than one database simultaneously,
regardless of whether or not those databases are attached to the same or
different database handles. Instead, a pool of schema objects is maintained 
for each unique sqlite&#95;master-contents/schema-cookie combination
opened within the process. Each time database schemas are required by a
connection, for example as part of an sqlite3&#95;prepare\*(),
sqlite3&#95;blob&#95;open() or sqlite3&#95;blob&#95;open() call, it obtains
the minimum number of schemas required from the various schema-pools, returning
them at the end of the call. This means that a single schema-pool only ever
contains more than one copy of the schema if:

  * Two threads require schemas from the same pool at the same time, or
  * A single sqlite3&#95;prepare\*() call requires schemas for two or more
    attached databases that use the same schema-pool.

The size of a schema-pool never shrinks. Each schema pool always maintains 
a number of schema objects equal to the highwater mark of schema objects
simultaneously required by clients.

This approach is preferred to allowing multiple databases to use the same
Schema object simultaneously for three reasons:

  * The Schema object is not completely read-only. For example, the 
    Index.zIdxAff string is allocated lazily.
  * Throughout the statement compiler, SQLite uses variables like 
    Table.pSchema and Index.pSchema with the sqlite3SchemaToIndex() routine
    in order to determine which attached database a Table or Index object
    resides in. This mechanism does not work if the same Schema may be
    used by two or more attached databases.
  * It may be easier to modify this approach in order to allow
    SQLITE&#95;OPEN&#95;SHARED&#95;SCHEMA connections to modify database
    schemas, should that be required.

SQLITE&#95;OPEN&#95;SHARED&#95;SCHEMA connections do not store their
virtual-table handles in the Table.pVTable list of each table. This would not
work, as (a) there is no guarantee that a connection will be assigned the same
Schema object each time it requests one from a schema-pool and (b) a single
Schema (and therefore Table) object may correspond to tables in two or more
databases attached to a single connection. Instead, all virtual-table handles
associated with a single database are stored in a linked-list headed at
Db.pVTable.

Changes to main.mk.

339
340
341
342
343
344
345

346
347
348
349
350
351
352
...
391
392
393
394
395
396
397

398
399
400
401
402
403
404
  $(TOP)/src/test_mutex.c \
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_quota.c \
  $(TOP)/src/test_rtree.c \
  $(TOP)/src/test_schema.c \

  $(TOP)/src/test_server.c \
  $(TOP)/src/test_sqllog.c \
  $(TOP)/src/test_superlock.c \
  $(TOP)/src/test_syscall.c \
  $(TOP)/src/test_tclsh.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/test_thread.c \
................................................................................
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

TESTSRC2 = \
  $(TOP)/src/attach.c \
  $(TOP)/src/backup.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/build.c \

  $(TOP)/src/date.c \
  $(TOP)/src/dbpage.c \
  $(TOP)/src/dbstat.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/func.c \
  $(TOP)/src/global.c \
  $(TOP)/src/insert.c \







>







 







>







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  $(TOP)/src/test_mutex.c \
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_quota.c \
  $(TOP)/src/test_rtree.c \
  $(TOP)/src/test_schema.c \
  $(TOP)/src/test_schemapool.c \
  $(TOP)/src/test_server.c \
  $(TOP)/src/test_sqllog.c \
  $(TOP)/src/test_superlock.c \
  $(TOP)/src/test_syscall.c \
  $(TOP)/src/test_tclsh.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/test_thread.c \
................................................................................
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

TESTSRC2 = \
  $(TOP)/src/attach.c \
  $(TOP)/src/backup.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/build.c \
  $(TOP)/src/callback.c \
  $(TOP)/src/date.c \
  $(TOP)/src/dbpage.c \
  $(TOP)/src/dbstat.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/func.c \
  $(TOP)/src/global.c \
  $(TOP)/src/insert.c \

Changes to src/alter.c.

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
** Generate code to reload the schema for database iDb. And, if iDb!=1, for
** the temp database as well.
*/
static void renameReloadSchema(Parse *pParse, int iDb){
  Vdbe *v = pParse->pVdbe;
  if( v ){
    sqlite3ChangeCookie(pParse, iDb);
    sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
    if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
  }
}

/*
** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" 
** command. 
*/







|
|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
** Generate code to reload the schema for database iDb. And, if iDb!=1, for
** the temp database as well.
*/
static void renameReloadSchema(Parse *pParse, int iDb){
  Vdbe *v = pParse->pVdbe;
  if( v ){
    sqlite3ChangeCookie(pParse, iDb);
    sqlite3VdbeAddParseSchemaOp(pParse, iDb, 0);
    if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse, 1, 0);
  }
}

/*
** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" 
** command. 
*/

Changes to src/analyze.c.

208
209
210
211
212
213
214

215
216
217
218
219
220
221
    aCreateTbl[i] = 0;
    if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
      if( i<nToOpen ){
        /* The sqlite_statN table does not exist. Create it. Note that a 
        ** side-effect of the CREATE TABLE statement is to leave the rootpage 
        ** of the new table in register pParse->regRoot. This is important 
        ** because the OpenWrite opcode below will be needing it. */

        sqlite3NestedParse(pParse,
            "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
        );
        aRoot[i] = (u32)pParse->regRoot;
        aCreateTbl[i] = OPFLAG_P2ISREG;
      }
    }else{







>







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
    aCreateTbl[i] = 0;
    if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
      if( i<nToOpen ){
        /* The sqlite_statN table does not exist. Create it. Note that a 
        ** side-effect of the CREATE TABLE statement is to leave the rootpage 
        ** of the new table in register pParse->regRoot. This is important 
        ** because the OpenWrite opcode below will be needing it. */
        sqlite3SchemaWritable(pParse, iDb);
        sqlite3NestedParse(pParse,
            "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
        );
        aRoot[i] = (u32)pParse->regRoot;
        aCreateTbl[i] = OPFLAG_P2ISREG;
      }
    }else{

Changes to src/attach.c.

201
202
203
204
205
206
207
208
209
210
211

212
213
214
215

216
217
218
219
220
221
222
...
306
307
308
309
310
311
312

313
314
315
316
317
318
319

  /* If the file was opened successfully, read the schema for the new database.
  ** If this fails, or if opening the file failed, then close the file and 
  ** remove the entry from the db->aDb[] array. i.e. put everything back the
  ** way we found it.
  */
  if( rc==SQLITE_OK ){
    sqlite3BtreeEnterAll(db);
    db->init.iDb = 0;
    db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
    if( !REOPEN_AS_MEMDB(db) ){

      rc = sqlite3Init(db, &zErrDyn);
    }
    sqlite3BtreeLeaveAll(db);
    assert( zErrDyn==0 || rc!=SQLITE_OK );

  }
#ifdef SQLITE_USER_AUTHENTICATION
  if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){
    u8 newAuth = 0;
    rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
    if( newAuth<db->auth.authLevel ){
      rc = SQLITE_AUTH_USER;
................................................................................
    Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
    if( pTrig->pTabSchema==pDb->pSchema ){
      pTrig->pTabSchema = pTrig->pSchema;
    }
    pEntry = sqliteHashNext(pEntry);
  }


  sqlite3BtreeClose(pDb->pBt);
  pDb->pBt = 0;
  pDb->pSchema = 0;
  sqlite3CollapseDatabaseArray(db);
  return;

detach_error:







<


|
>

<
|
|
>







 







>







201
202
203
204
205
206
207

208
209
210
211
212

213
214
215
216
217
218
219
220
221
222
...
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

  /* If the file was opened successfully, read the schema for the new database.
  ** If this fails, or if opening the file failed, then close the file and 
  ** remove the entry from the db->aDb[] array. i.e. put everything back the
  ** way we found it.
  */
  if( rc==SQLITE_OK ){

    db->init.iDb = 0;
    db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
    if( !IsSharedSchema(db) && !REOPEN_AS_MEMDB(db) ){
      sqlite3BtreeEnterAll(db);
      rc = sqlite3Init(db, &zErrDyn);

      sqlite3BtreeLeaveAll(db);
      assert( zErrDyn==0 || rc!=SQLITE_OK );
    }
  }
#ifdef SQLITE_USER_AUTHENTICATION
  if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){
    u8 newAuth = 0;
    rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
    if( newAuth<db->auth.authLevel ){
      rc = SQLITE_AUTH_USER;
................................................................................
    Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
    if( pTrig->pTabSchema==pDb->pSchema ){
      pTrig->pTabSchema = pTrig->pSchema;
    }
    pEntry = sqliteHashNext(pEntry);
  }

  sqlite3SchemaDisconnect(db, i, 0);
  sqlite3BtreeClose(pDb->pBt);
  pDb->pBt = 0;
  pDb->pSchema = 0;
  sqlite3CollapseDatabaseArray(db);
  return;

detach_error:

Changes to src/build.c.

292
293
294
295
296
297
298

































299
300
301
302
303
304
305
...
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
...
394
395
396
397
398
399
400

401
402
403
404
405
406
407
...
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
...
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
....
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
....
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
....
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068

3069
3070
3071
3072
3073
3074
3075
....
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
....
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
....
4141
4142
4143
4144
4145
4146
4147

4148
4149
4150
4151
4152
4153
4154
** list of users and their access credentials.
*/
int sqlite3UserAuthTable(const char *zTable){
  return sqlite3_stricmp(zTable, "sqlite_user")==0;
}
#endif


































/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.
**
** If zDatabase is 0, all databases are searched for the table and the
** first matching table is returned.  (No checking for duplicate table
................................................................................
#if SQLITE_USER_AUTHENTICATION
  /* Only the admin user is allowed to know that the sqlite_user table
  ** exists */
  if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
    return 0;
  }
#endif
  if( zDatabase ){
    for(i=0; i<db->nDb; i++){
      if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
    }
    if( i>=db->nDb ){
      /* No match against the official names.  But always match "main"
      ** to schema 0 as a legacy fallback. */
      if( sqlite3StrICmp(zDatabase,"main")==0 ){
        i = 0;
      }else{
        return 0;
      }
    }
    p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
    if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
      if( i==1 ){
        if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0
         || sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0
         || sqlite3StrICmp(zName+7, &DFLT_SCHEMA_TABLE[7])==0
        ){
          p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, 
                              DFLT_TEMP_SCHEMA_TABLE);
        }
      }else{
        if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
          p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash,
                              DFLT_SCHEMA_TABLE);
        }
      }
    }
  }else{
    /* Match against TEMP first */
    p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
    if( p ) return p;
    /* The main database is second */
    p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
    if( p ) return p;
    /* Attached databases are in order of attachment */
    for(i=2; i<db->nDb; i++){
      assert( sqlite3SchemaMutexHeld(db, i, 0) );
      p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
      if( p ) break;
    }
    if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
      if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
        p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, DFLT_SCHEMA_TABLE);
      }else if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0 ){
        p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, 
                            DFLT_TEMP_SCHEMA_TABLE);
      }
    }
  }
  return p;
}

/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.  Also leave an
** error message in pParse->zErrMsg.
................................................................................
){
  Table *p;
  sqlite3 *db = pParse->db;

  /* Read the database schema. If an error occurs, leave an error message
  ** and code in pParse and return NULL. */
  if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 

   && SQLITE_OK!=sqlite3ReadSchema(pParse)
  ){
    return 0;
  }

  p = sqlite3FindTable(db, zName, zDbase);
  if( p==0 ){
................................................................................
    ** CREATE, then check to see if it is the name of an virtual table that
    ** can be an eponymous virtual table. */
    if( pParse->disableVtab==0 ){
      Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
      if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
        pMod = sqlite3PragmaVtabRegister(db, zName);
      }






      if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
        return pMod->pEpoTab;




      }
    }
#endif
    if( flags & LOCATE_NOERR ) return 0;
    pParse->checkSchema = 1;
  }else if( IsVirtual(p) && pParse->disableVtab ){
    p = 0;
  }

  if( p==0 ){
    const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
    if( zDbase ){
      sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    }else{
      sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    }
  }
................................................................................

  if( iDb>=0 ){
    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    DbSetProperty(db, iDb, DB_ResetWanted);
    DbSetProperty(db, 1, DB_ResetWanted);
    db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
  }

  if( db->nSchemaLock==0 ){
    for(i=0; i<db->nDb; i++){
      if( DbHasProperty(db, i, DB_ResetWanted) ){
        sqlite3SchemaClear(db->aDb[i].pSchema);
      }
    }
  }
}

/*
** Erase all schema information from all attached databases (including
** "main" and "temp") for a single database connection.
*/
void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
  int i;
  sqlite3BtreeEnterAll(db);
  for(i=0; i<db->nDb; i++){
    Db *pDb = &db->aDb[i];
    if( pDb->pSchema ){
      if( db->nSchemaLock==0 ){
        sqlite3SchemaClear(pDb->pSchema);
      }else{
        DbSetProperty(db, i, DB_ResetWanted);
      }
    }
  }

  db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk);
  sqlite3VtabUnlockList(db);
  sqlite3BtreeLeaveAll(db);
  if( db->nSchemaLock==0 ){
    sqlite3CollapseDatabaseArray(db);
  }
}
................................................................................
  ** it does. The exception is if the statement being parsed was passed
  ** to an sqlite3_declare_vtab() call. In that case only the column names
  ** and types will be used, so there is no need to test for namespace
  ** collisions.
  */
  if( !IN_SPECIAL_PARSE ){
    char *zDb = db->aDb[iDb].zDbSName;
    if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
      goto begin_table_error;
    }
    pTable = sqlite3FindTable(db, zName, zDb);
    if( pTable ){
      if( !noErr ){
        sqlite3ErrorMsg(pParse, "table %T already exists", pName);
      }else{
................................................................................
          pDb->zDbSName
        );
      }
    }
#endif

    /* Reparse everything to update our internal data structures */
    sqlite3VdbeAddParseSchemaOp(v, iDb,
           sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
  }

  /* Add the table to the in-memory representation of the database.
  */
  if( db->init.busy ){
    Table *pOld;
................................................................................
  int iDb;

  if( db->mallocFailed ){
    goto exit_drop_table;
  }
  assert( pParse->nErr==0 );
  assert( pName->nSrc==1 );
  if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
  if( noErr ) db->suppressErr++;
  assert( isView==0 || isView==LOCATE_VIEW );
  pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
  if( noErr ) db->suppressErr--;

  if( pTab==0 ){
    if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
    goto exit_drop_table;
  }
  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  assert( iDb>=0 && iDb<db->nDb );


  /* If pTab is a virtual table, call ViewGetColumnNames() to ensure
  ** it is initialized.
  */
  if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
    goto exit_drop_table;
  }
................................................................................

  if( db->mallocFailed || pParse->nErr>0 ){
    goto exit_create_index;
  }
  if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
    goto exit_create_index;
  }
  if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    goto exit_create_index;
  }
  if( sqlite3HasExplicitNulls(pParse, pList) ){
    goto exit_create_index;
  }

  /*
................................................................................

      /* Fill the index with data and reparse the schema. Code an OP_Expire
      ** to invalidate all pre-compiled statements.
      */
      if( pTblName ){
        sqlite3RefillIndex(pParse, pIndex, iMem);
        sqlite3ChangeCookie(pParse, iDb);
        sqlite3VdbeAddParseSchemaOp(v, iDb,
            sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
        sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
      }

      sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
    }
  }
................................................................................
  }
  if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
    sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
      "or PRIMARY KEY constraint cannot be dropped", 0);
    goto exit_drop_index;
  }
  iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);

#ifndef SQLITE_OMIT_AUTHORIZATION
  {
    int code = SQLITE_DROP_INDEX;
    Table *pTab = pIndex->pTable;
    const char *zDb = db->aDb[iDb].zDbSName;
    const char *zTab = SCHEMA_TABLE(iDb);
    if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){







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







 







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







 







>







 







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









|







 







<



|












|



|





>







 







|







 







|







 







|











>







 







|







 







|







 







>







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
...
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
...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
...
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
...
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
637
638
639
640
641
642
643
644
645
646
....
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
....
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
....
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
....
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
....
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
....
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
** list of users and their access credentials.
*/
int sqlite3UserAuthTable(const char *zTable){
  return sqlite3_stricmp(zTable, "sqlite_user")==0;
}
#endif

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
/*
** If this database connection was opened with the SQLITE_OPEN_SHARED_SCHEMA
** flag specified, then ensure that the database schema for database iDb
** is loaded. Either by obtaining a Schema object from the schema-pool, or
** by reading the contents of the sqlite_master table. Unless it is NULL, 
** the location indicated by parameter pbUnload is set to 1 if a shared-schema 
** is loaded.
**
** If the database handle was not opened with SQLITE_OPEN_SHARED_SCHEMA, or
** if the schema for database iDb is already loaded, this function is a no-op.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise. If
** an error code is returned, (*pzErr) may be set to point to a buffer
** containing an error message. It is the responsibility of the caller to
** eventually free this buffer using sqlite3_free().
*/
int sqlite3SchemaLoad(sqlite3 *db, int iDb, int *pbUnload, char **pzErr){
  int rc = SQLITE_OK;
  if( IsSharedSchema(db) 
      && DbHasProperty(db, iDb, DB_SchemaLoaded)==0 
      && (db->init.busy==0 || (iDb!=1 && db->init.iDb==1))
  ){
    struct sqlite3InitInfo sv = db->init;
    memset(&db->init, 0, sizeof(struct sqlite3InitInfo));
    rc = sqlite3InitOne(db, iDb, pzErr, 0);
    db->init = sv;
    if( pbUnload && rc==SQLITE_OK && iDb!=1 ) *pbUnload = 1;
  }
  return rc;
}
#endif

/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.
**
** If zDatabase is 0, all databases are searched for the table and the
** first matching table is returned.  (No checking for duplicate table
................................................................................
#if SQLITE_USER_AUTHENTICATION
  /* Only the admin user is allowed to know that the sqlite_user table
  ** exists */
  if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
    return 0;
  }
#endif
  while(1){
    for(i=OMIT_TEMPDB; i<db->nDb; i++){
      int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
      if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){
        int bUnload = 0;
        assert( sqlite3SchemaMutexHeld(db, j, 0) );
        if( IsSharedSchema(db) ){
          Parse *pParse = db->pParse;
          if( pParse && pParse->nErr==0 ){
            pParse->rc = sqlite3SchemaLoad(db, j, &bUnload, &pParse->zErrMsg);
            if( pParse->rc ) pParse->nErr++;
          }
        }
        p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
        if( p ) return p;
        if( bUnload ){
          sqlite3SchemaRelease(db, j);
        }
      }
    }
    /* Not found.  If the name we were looking for was temp.sqlite_master
    ** then change the name to sqlite_temp_master and try again. */
    if( sqlite3StrICmp(zName, ALT_SCHEMA_TABLE)==0 ){
      zName = DFLT_SCHEMA_TABLE;
      continue;
    }
    if( sqlite3StrICmp(zName, ALT_TEMP_SCHEMA_TABLE)==0 ){
      zName = DFLT_TEMP_SCHEMA_TABLE;
      continue;
    }
    if( sqlite3StrICmp(zName, DFLT_SCHEMA_TABLE)!=0 ) break;
    if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
    zName = DFLT_TEMP_SCHEMA_TABLE;
  }
  return 0;


















}

/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
** database containing the table.  Return NULL if not found.  Also leave an
** error message in pParse->zErrMsg.
................................................................................
){
  Table *p;
  sqlite3 *db = pParse->db;

  /* Read the database schema. If an error occurs, leave an error message
  ** and code in pParse and return NULL. */
  if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 
   && !IsSharedSchema(db)
   && SQLITE_OK!=sqlite3ReadSchema(pParse)
  ){
    return 0;
  }

  p = sqlite3FindTable(db, zName, zDbase);
  if( p==0 ){
................................................................................
    ** CREATE, then check to see if it is the name of an virtual table that
    ** can be an eponymous virtual table. */
    if( pParse->disableVtab==0 ){
      Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
      if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
        pMod = sqlite3PragmaVtabRegister(db, zName);
      }
      if( pMod ){
        if( IsSharedSchema(db) && pParse->nErr==0 ){
          int bDummy = 0;
          pParse->rc = sqlite3SchemaLoad(db, 0, &bDummy, &pParse->zErrMsg);
          if( pParse->rc ) pParse->nErr++;
        }
        if( sqlite3VtabEponymousTableInit(pParse, pMod) ){
          Table *pEpoTab = pMod->pEpoTab;
          assert( IsSharedSchema(db) || pEpoTab->pSchema==db->aDb[0].pSchema );
          pEpoTab->pSchema = db->aDb[0].pSchema;  /* For SHARED_SCHEMA mode */
          return pEpoTab;
        }
      }
    }
#endif
    if( flags & LOCATE_NOERR ) return 0;
    pParse->checkSchema = 1;
  }else if( IsVirtual(p) && pParse->disableVtab ){
    p = 0;
  }

  if( p==0 && (!IsSharedSchema(db) || pParse->nErr==0) ){
    const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
    if( zDbase ){
      sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    }else{
      sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    }
  }
................................................................................

  if( iDb>=0 ){
    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    DbSetProperty(db, iDb, DB_ResetWanted);
    DbSetProperty(db, 1, DB_ResetWanted);
    db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
  }

  if( db->nSchemaLock==0 ){
    for(i=0; i<db->nDb; i++){
      if( DbHasProperty(db, i, DB_ResetWanted) ){
        sqlite3SchemaClearOrDisconnect(db, i);
      }
    }
  }
}

/*
** Erase all schema information from all attached databases (including
** "main" and "temp") for a single database connection.
*/
void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
  int i;
  sqlite3BtreeEnterAll(db);
  for(i=0; i<db->nDb; i=(i?i+1:2)){
    Db *pDb = &db->aDb[i];
    if( pDb->pSchema ){
      if( db->nSchemaLock==0 ){
        sqlite3SchemaClearOrDisconnect(db, i);
      }else{
        DbSetProperty(db, i, DB_ResetWanted);
      }
    }
  }
  sqlite3SchemaClear(db->aDb[1].pSchema);
  db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk);
  sqlite3VtabUnlockList(db);
  sqlite3BtreeLeaveAll(db);
  if( db->nSchemaLock==0 ){
    sqlite3CollapseDatabaseArray(db);
  }
}
................................................................................
  ** it does. The exception is if the statement being parsed was passed
  ** to an sqlite3_declare_vtab() call. In that case only the column names
  ** and types will be used, so there is no need to test for namespace
  ** collisions.
  */
  if( !IN_SPECIAL_PARSE ){
    char *zDb = db->aDb[iDb].zDbSName;
    if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){
      goto begin_table_error;
    }
    pTable = sqlite3FindTable(db, zName, zDb);
    if( pTable ){
      if( !noErr ){
        sqlite3ErrorMsg(pParse, "table %T already exists", pName);
      }else{
................................................................................
          pDb->zDbSName
        );
      }
    }
#endif

    /* Reparse everything to update our internal data structures */
    sqlite3VdbeAddParseSchemaOp(pParse, iDb,
           sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
  }

  /* Add the table to the in-memory representation of the database.
  */
  if( db->init.busy ){
    Table *pOld;
................................................................................
  int iDb;

  if( db->mallocFailed ){
    goto exit_drop_table;
  }
  assert( pParse->nErr==0 );
  assert( pName->nSrc==1 );
  if( !IsSharedSchema(db) && sqlite3ReadSchema(pParse) ) goto exit_drop_table;
  if( noErr ) db->suppressErr++;
  assert( isView==0 || isView==LOCATE_VIEW );
  pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
  if( noErr ) db->suppressErr--;

  if( pTab==0 ){
    if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
    goto exit_drop_table;
  }
  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  assert( iDb>=0 && iDb<db->nDb );
  sqlite3SchemaWritable(pParse, iDb);

  /* If pTab is a virtual table, call ViewGetColumnNames() to ensure
  ** it is initialized.
  */
  if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
    goto exit_drop_table;
  }
................................................................................

  if( db->mallocFailed || pParse->nErr>0 ){
    goto exit_create_index;
  }
  if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
    goto exit_create_index;
  }
  if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    goto exit_create_index;
  }
  if( sqlite3HasExplicitNulls(pParse, pList) ){
    goto exit_create_index;
  }

  /*
................................................................................

      /* Fill the index with data and reparse the schema. Code an OP_Expire
      ** to invalidate all pre-compiled statements.
      */
      if( pTblName ){
        sqlite3RefillIndex(pParse, pIndex, iMem);
        sqlite3ChangeCookie(pParse, iDb);
        sqlite3VdbeAddParseSchemaOp(pParse, iDb,
            sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
        sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
      }

      sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
    }
  }
................................................................................
  }
  if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
    sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
      "or PRIMARY KEY constraint cannot be dropped", 0);
    goto exit_drop_index;
  }
  iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
  sqlite3SchemaWritable(pParse, iDb);
#ifndef SQLITE_OMIT_AUTHORIZATION
  {
    int code = SQLITE_DROP_INDEX;
    Table *pTab = pIndex->pTable;
    const char *zDb = db->aDb[iDb].zDbSName;
    const char *zTab = SCHEMA_TABLE(iDb);
    if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){

Changes to src/callback.c.

12
13
14
15
16
17
18

























































19
20
21
22
23
24
25
...
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
**
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
*/

#include "sqliteInt.h"


























































/*
** Invoke the 'collation needed' callback to request a collation sequence
** in the encoding enc of name zName, length nName.
*/
static void callCollNeeded(sqlite3 *db, int enc, const char *zName){
  assert( !db->xCollNeeded || !db->xCollNeeded16 );
  if( db->xCollNeeded ){
................................................................................
  if( pSchema->schemaFlags & DB_SchemaLoaded ){
    pSchema->iGeneration++;
  }
  pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}

/*
** Find and return the schema associated with a BTree.  Create
** a new one if necessary.





*/









































































































































































































































































































Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
  Schema * p;
  if( pBt ){
    p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
  }else{
    p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
  }
  if( !p ){
    sqlite3OomFault(db);
  }else if ( 0==p->file_format ){
    sqlite3HashInit(&p->tblHash);
    sqlite3HashInit(&p->idxHash);
    sqlite3HashInit(&p->trigHash);
    sqlite3HashInit(&p->fkeyHash);
    p->enc = SQLITE_UTF8;
  }
  return p;
}







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







 







|
|
>
>
>
>
>

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

|
|
|

|












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
...
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
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
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
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
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
**
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
*/

#include "sqliteInt.h"

/*
** Connections opened with the SQLITE_OPEN_SHARED_SCHEMA flag specified
** may use SchemaPool objects for any database that is not the temp db
** (iDb==1). For such databases (type "struct Db") there are three states
** the Schema/SchemaPool object may be in.
**
**   1) pSPool==0, pSchema points to an empty object allocated by
**      sqlite3_malloc(). DB_SchemaLoaded flag is clear.
**
**   2) pSPool!=0, pSchema points to a populated object owned by the
**      SchemaPool. DB_SchemaLoaded flag is set.
**
**   3) pSPool!=0, pSchema points to the SchemaPool's static object
**      (SchemaPool.sSchema).
*/
struct SchemaPool {
  int nRef;                       /* Number of pointers to this object */
  int nDelete;                    /* Schema objects deleted by ReleaseAll() */
  u64 cksum;                      /* Checksum for this Schema contents */
  Schema *pSchema;                /* Linked list of Schema objects */
  Schema sSchema;                 /* The single dummy schema object */
  SchemaPool *pNext;              /* Next element in schemaPoolList */
};

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
#ifdef SQLITE_DEBUG
static void assert_schema_state_ok(sqlite3 *db){
  if( IsSharedSchema(db) && db->magic!=SQLITE_MAGIC_ZOMBIE ){
    int i;
    for(i=0; i<db->nDb; i++){
      if( i!=1 ){
        Db *pDb = &db->aDb[i];
        Btree *pBt = pDb->pBt;
        if( pBt==0 ) continue;
        assert( sqlite3BtreeSchema(pBt, 0, 0)==0 );
        assert( pDb->pSchema );
        if( pDb->pSPool ){
          if( DbHasProperty(db, i, DB_SchemaLoaded)==0 ){
            assert( pDb->pSchema->tblHash.count==0 );
            assert( pDb->pSchema==&pDb->pSPool->sSchema );
          }else{
            assert( pDb->pSchema!=&pDb->pSPool->sSchema );
          }
        }else{
          assert( DbHasProperty(db, i, DB_SchemaLoaded)==0 );
          assert( pDb->pSchema->tblHash.count==0 );
          assert( pDb->pSchema!=&pDb->pSPool->sSchema );
        }
      }
    }
  }
}
#else
# define assert_schema_state_ok(x)
#endif
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */

/*
** Invoke the 'collation needed' callback to request a collation sequence
** in the encoding enc of name zName, length nName.
*/
static void callCollNeeded(sqlite3 *db, int enc, const char *zName){
  assert( !db->xCollNeeded || !db->xCollNeeded16 );
  if( db->xCollNeeded ){
................................................................................
  if( pSchema->schemaFlags & DB_SchemaLoaded ){
    pSchema->iGeneration++;
  }
  pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}

/*
** If this database was opened with the SQLITE_OPEN_SHARED_SCHEMA flag
** and iDb!=1, then disconnect from the schema-pool associated with
** database iDb. Otherwise, clear the Schema object belonging to
** database iDb. 
**
** If an OOM error occurs while disconnecting from a schema-pool, 
** the db->mallocFailed flag is set.
*/
void sqlite3SchemaClearOrDisconnect(sqlite3 *db, int iDb){
  Db *pDb = &db->aDb[iDb];
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  if( IsSharedSchema(db) && iDb!=1 && pDb->pSPool ){
    sqlite3SchemaDisconnect(db, iDb, 1);
  }else
#endif
  {
    sqlite3SchemaClear(pDb->pSchema);
  }
}

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
/*
** Global linked list of SchemaPool objects. Read and write access must
** be protected by the SQLITE_MUTEX_STATIC_MASTER mutex.
*/
static SchemaPool *SQLITE_WSD schemaPoolList = 0;

#ifdef SQLITE_TEST
/*
** Return a pointer to the head of the linked list of SchemaPool objects.
** This is used by the virtual table in file test_schemapool.c.
*/
SchemaPool *sqlite3SchemaPoolList(void){ return schemaPoolList; }
#endif

/*
** Database handle db was opened with the SHARED_SCHEMA flag, and database
** iDb is currently connected to a schema-pool. When this function is called,
** (*pnByte) is set to nInit plus the amount of memory used to store a 
** single instance of the Schema objects managed by the schema-pool.
** This function adjusts (*pnByte) sot hat it is set to nInit plus
** (nSchema/nRef) of the amount of memory used by a single Schema object,
** where nSchema is the number of Schema objects allocated by this pool,
** and nRef is the number of connections to the schema-pool.
*/
void sqlite3SchemaAdjustUsed(sqlite3 *db, int iDb, int nInit, int *pnByte){
  SchemaPool *pSPool = db->aDb[iDb].pSPool;
  int nSchema = 0;
  Schema *p;
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  for(p=pSPool->pSchema; p; p=p->pNext){
    nSchema++;
  }
  *pnByte = nInit + ((*pnByte - nInit) * nSchema) / pSPool->nRef;
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}

/*
** Check that the schema of db iDb is writable (either because it is the 
** temp db schema or because the db handle was opened without
** SQLITE_OPEN_SHARED_SCHEMA). If so, do nothing. Otherwise, leave an 
** error in the Parse object.
*/
void sqlite3SchemaWritable(Parse *pParse, int iDb){
  if( iDb!=1 && IsSharedSchema(pParse->db) && IN_DECLARE_VTAB==0 ){
    sqlite3ErrorMsg(pParse, "attempt to modify read-only schema");
  }
}

/*
** The schema object passed as the only argument was allocated using
** sqlite3_malloc() and then populated using the usual mechanism. This
** function frees both the Schema object and its contents.
*/
static void schemaDelete(Schema *pSchema){
  sqlite3SchemaClear((void*)pSchema);
  sqlite3_free(pSchema);
}

/*
** When this function is called, the database connection Db must be
** using a schema-pool (Db.pSPool!=0) and must currently have Db.pSchema
** set to point to a populated schema object checked out from the 
** schema-pool. It is also assumed that the STATIC_MASTER mutex is held.
** This function returns the Schema object to the schema-pool and sets
** Db.pSchema to point to the schema-pool's static, empty, Schema object.
*/
static void schemaRelease(sqlite3 *db, Db *pDb){
  Schema *pRelease = pDb->pSchema;
  SchemaPool *pSPool = pDb->pSPool;

  assert( pDb->pSchema->iGeneration==pSPool->sSchema.iGeneration );
  pDb->pSchema = &pSPool->sSchema;

  assert( pDb->pSPool && pRelease );
  assert( pRelease->schemaFlags & DB_SchemaLoaded );
  assert( (pDb->pSchema->schemaFlags & DB_SchemaLoaded)==0 );
  assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) );

  /* If the DBFLAG_FreeSchema flag is set and the database connection holds
  ** at least one other copy of the schema being released, delete it instead
  ** of returning it to the schema-pool.  */
  if( db->mDbFlags & DBFLAG_FreeSchema ){
    int i;
    for(i=0; i<db->nDb; i++){
      Db *p = &db->aDb[i];
      if( p!=pDb && p->pSchema!=&pSPool->sSchema && pDb->pSPool==p->pSPool ){
        pSPool->nDelete++;
        schemaDelete(pRelease);
        return;
      }
    }
  }

  pRelease->pNext = pDb->pSPool->pSchema;
  pDb->pSPool->pSchema = pRelease;
}

/*
** The schema for database iDb of database handle db, which was opened
** with SQLITE_OPEN_SHARED_SCHEMA, has just been parsed. This function either
** finds a matching SchemaPool object on the global list (schemaPoolList) or
** else allocates a new one and sets the Db.pSPool variable accordingly.
**
** SQLITE_OK is returned if no error occurs, or an SQLite error code 
** (SQLITE_NOMEM) otherwise.
*/
int sqlite3SchemaConnect(sqlite3 *db, int iDb, u64 cksum){
  Schema *pSchema = db->aDb[iDb].pSchema;
  SchemaPool *p;

  assert( pSchema && iDb!=1 && db->aDb[iDb].pSPool==0 );

  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );

  /* Search for a matching SchemaPool object */
  for(p=schemaPoolList; p; p=p->pNext){
    if( p->cksum==cksum && p->sSchema.schema_cookie==pSchema->schema_cookie ){
      break;
    }
  }
  if( !p ){
    /* No SchemaPool object found. Allocate a new one. */
    p = (SchemaPool*)sqlite3_malloc(sizeof(SchemaPool));
    if( p ){
      memset(p, 0, sizeof(SchemaPool));
      p->cksum = cksum;
      p->pNext = schemaPoolList;
      schemaPoolList = p;

      p->sSchema.schema_cookie = pSchema->schema_cookie;
      p->sSchema.iGeneration = pSchema->iGeneration;
      p->sSchema.file_format = pSchema->file_format;
      p->sSchema.enc = pSchema->enc;
      p->sSchema.cache_size = pSchema->cache_size;
    }
  }

  if( p ) p->nRef++;

  /* If the SchemaPool contains one or more free schemas at the moment, 
  ** delete one of them. */
  if( p && p->pSchema ){
    Schema *pDel = p->pSchema;
    p->pSchema = pDel->pNext;
    schemaDelete(pDel);
  }

  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );

  db->aDb[iDb].pSPool = p;
  return (p ? SQLITE_OK : SQLITE_NOMEM);
}

/*
** If parameter iDb is 1 (the temp db), or if connection handle db was not
** opened with the SQLITE_OPEN_SHARED_SCHEMA flag, this function is a no-op.
** Otherwise, it disconnects from the schema-pool associated with database
** iDb, assuming it is connected.
**
** If parameter bNew is true, then Db.pSchema is set to point to a new, empty,
** Schema object obtained from sqlite3_malloc(). Or, if bNew is false, then
** Db.pSchema is set to NULL before returning.
**
** If the bNew parameter is true, then this function may allocate memory. 
** If the allocation attempt fails, then SQLITE_NOMEM is returned and the
** schema-pool is not disconnected from. Or, if no OOM error occurs, 
** SQLITE_OK is returned.
*/
int sqlite3SchemaDisconnect(sqlite3 *db, int iDb, int bNew){
  int rc = SQLITE_OK;
  if( IsSharedSchema(db) ){
    Db *pDb = &db->aDb[iDb];
    SchemaPool *pSPool = pDb->pSPool;
    assert_schema_state_ok(db);
    assert( pDb->pSchema );

    if( pSPool==0 ){
      assert( pDb->pVTable==0 );
      assert( bNew==0 );
      schemaDelete(pDb->pSchema);
      pDb->pSchema = 0;
    }else{
      VTable *p;
      VTable *pNext;
      for(p=pDb->pVTable; p; p=pNext){
        pNext = p->pNext;
        sqlite3VtabUnlock(p);
      }
      pDb->pVTable = 0;
      sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
      if( DbHasProperty(db, iDb, DB_SchemaLoaded) ){
        schemaRelease(db, pDb);
      }
      if( bNew ){
        Schema *pNew = sqlite3SchemaGet(db, 0);
        if( pNew==0 ){
          rc = SQLITE_NOMEM;
        }else{
          pDb->pSchema = pNew;
        }
      }
      if( rc==SQLITE_OK ){
        assert( pSPool->nRef>=1 );
        pDb->pSPool = 0;
        pSPool->nRef--;
        if( pSPool->nRef<=0 ){
          SchemaPool **pp;
          while( pSPool->pSchema ){
            Schema *pNext = pSPool->pSchema->pNext;
            schemaDelete(pSPool->pSchema);
            pSPool->pSchema = pNext;
          }
          for(pp=&schemaPoolList; (*pp)!=pSPool; pp=&((*pp)->pNext));
          *pp = pSPool->pNext;
          sqlite3_free(pSPool);
        }
      }
      sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
    }
  }
  return rc;
}

/*
** Extract and return a pointer to a schema object from the SchemaPool passed
** as the only argument, if one is available. If one is not available, return
** NULL.
*/
Schema *sqlite3SchemaExtract(SchemaPool *pSPool){
  Schema *pRet = 0;
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  if( pSPool->pSchema ){
    pRet = pSPool->pSchema;
    pSPool->pSchema = pRet->pNext;
    pRet->pNext = 0;
  }
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  return pRet;
}

/*
** Return all sharable schemas held by database handle db back to their
** respective schema-pools. Db.pSchema variables are left pointing to
** the static, empty, Schema object owned by each schema-pool.
*/
void sqlite3SchemaReleaseAll(sqlite3 *db){
  int i;
  assert_schema_state_ok(db);
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  for(i=0; i<db->nDb; i++){
    if( i!=1 ){
      Db *pDb = &db->aDb[i];
      if( pDb->pSPool && DbHasProperty(db,i,DB_SchemaLoaded) ){
        schemaRelease(db, pDb);
      }
    }
  }
  db->mDbFlags &= ~DBFLAG_FreeSchema;
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}

/*
** Release any sharable schema held by connection iDb of database handle
** db. Db.pSchema is left pointing to the static, empty, Schema object
** owned by the schema-pool.
*/
void sqlite3SchemaRelease(sqlite3 *db, int iDb){
  Db *pDb = &db->aDb[iDb];
  assert( iDb!=1 );
  assert_schema_state_ok(db);
  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
  schemaRelease(db, pDb);
  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}

#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */

/*
** In most cases, this function finds and returns the schema associated 
** with BTree handle pBt, creating a new one if necessary. However, if
** the database handle was opened with the SQLITE_OPEN_SHARED_SCHEMA flag
** specified, a new, empty, Schema object in memory obtained by 
** sqlite3_malloc() is always returned.
*/
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
  Schema *p;
  if( pBt && IsSharedSchema(db)==0 ){
    p = (Schema*)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
  }else{
    p = (Schema*)sqlite3DbMallocZero(0, sizeof(Schema));
  }
  if( !p ){
    sqlite3OomFault(db);
  }else if ( 0==p->file_format ){
    sqlite3HashInit(&p->tblHash);
    sqlite3HashInit(&p->idxHash);
    sqlite3HashInit(&p->trigHash);
    sqlite3HashInit(&p->fkeyHash);
    p->enc = SQLITE_UTF8;
  }
  return p;
}

Changes to src/ctime.c.

293
294
295
296
297
298
299



300
301
302
303
304
305
306
  "ENABLE_RTREE",
#endif
#if SQLITE_ENABLE_SELECTTRACE
  "ENABLE_SELECTTRACE",
#endif
#if SQLITE_ENABLE_SESSION
  "ENABLE_SESSION",



#endif
#if SQLITE_ENABLE_SNAPSHOT
  "ENABLE_SNAPSHOT",
#endif
#if SQLITE_ENABLE_SORTER_REFERENCES
  "ENABLE_SORTER_REFERENCES",
#endif







>
>
>







293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  "ENABLE_RTREE",
#endif
#if SQLITE_ENABLE_SELECTTRACE
  "ENABLE_SELECTTRACE",
#endif
#if SQLITE_ENABLE_SESSION
  "ENABLE_SESSION",
#endif
#if SQLITE_ENABLE_SHARED_SCHEMA
  "ENABLE_SHARED_SCHEMA",
#endif
#if SQLITE_ENABLE_SNAPSHOT
  "ENABLE_SNAPSHOT",
#endif
#if SQLITE_ENABLE_SORTER_REFERENCES
  "ENABLE_SORTER_REFERENCES",
#endif

Changes to src/fkey.c.

1409
1410
1411
1412
1413
1414
1415

1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash
** hash table.
*/
void sqlite3FkDelete(sqlite3 *db, Table *pTab){
  FKey *pFKey;                    /* Iterator variable */
  FKey *pNext;                    /* Copy of pFKey->pNextFrom */


  assert( db==0 || IsVirtual(pTab)
         || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
  for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){

    /* Remove the FK from the fkeyHash hash table. */
    if( !db || db->pnBytesFreed==0 ){
      if( pFKey->pPrevTo ){
        pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
      }else{
        void *p = (void *)pFKey->pNextTo;







>
|

<







1409
1410
1411
1412
1413
1414
1415
1416
1417
1418

1419
1420
1421
1422
1423
1424
1425
** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash
** hash table.
*/
void sqlite3FkDelete(sqlite3 *db, Table *pTab){
  FKey *pFKey;                    /* Iterator variable */
  FKey *pNext;                    /* Copy of pFKey->pNextFrom */

  for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
    assert( db==0 || IsVirtual(pTab)
         || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );


    /* Remove the FK from the fkeyHash hash table. */
    if( !db || db->pnBytesFreed==0 ){
      if( pFKey->pPrevTo ){
        pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
      }else{
        void *p = (void *)pFKey->pNextTo;

Changes to src/main.c.

1155
1156
1157
1158
1159
1160
1161











1162
1163
1164
1165
1166
1167
1168
....
1293
1294
1295
1296
1297
1298
1299

1300
1301
1302
1303
1304
1305
1306
....
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671

3672

3673
3674
3675
3676
3677
3678







3679








3680
3681
3682
3683
3684
3685
3686
....
3745
3746
3747
3748
3749
3750
3751

3752
3753
3754
3755
3756
3757
3758
    Schema *pSchema = db->aDb[i].pSchema;
    if( pSchema ){
      for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
        Table *pTab = (Table *)sqliteHashData(p);
        if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
      }
    }











  }
  for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){
    Module *pMod = (Module *)sqliteHashData(p);
    if( pMod->pEpoTab ){
      sqlite3VtabDisconnect(db, pMod->pEpoTab);
    }
  }
................................................................................
  /* Close all database connections */
  for(j=0; j<db->nDb; j++){
    struct Db *pDb = &db->aDb[j];
    if( pDb->pBt ){
      sqlite3BtreeClose(pDb->pBt);
      pDb->pBt = 0;
      if( j!=1 ){

        pDb->pSchema = 0;
      }
    }
  }
  /* Clear the TEMP schema separately and last */
  if( db->aDb[1].pSchema ){
    sqlite3SchemaClear(db->aDb[1].pSchema);
................................................................................
  const char *zColumnName,    /* Column name */
  char const **pzDataType,    /* OUTPUT: Declared data type */
  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */
  int *pNotNull,              /* OUTPUT: True if NOT NULL constraint exists */
  int *pPrimaryKey,           /* OUTPUT: True if column part of PK */
  int *pAutoinc               /* OUTPUT: True if column is auto-increment */
){
  int rc;
  char *zErrMsg = 0;
  Table *pTab = 0;
  Column *pCol = 0;
  int iCol = 0;
  char const *zDataType = 0;
  char const *zCollSeq = 0;
  int notnull = 0;
  int primarykey = 0;
  int autoinc = 0;


#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif

  /* Ensure the database schema has been loaded */
  sqlite3_mutex_enter(db->mutex);

  sqlite3BtreeEnterAll(db);

  rc = sqlite3Init(db, &zErrMsg);
  if( SQLITE_OK!=rc ){
    goto error_out;
  }

  /* Locate the table in question */







  pTab = sqlite3FindTable(db, zTableName, zDbName);








  if( !pTab || pTab->pSelect ){
    pTab = 0;
    goto error_out;
  }

  /* Find the column for which info is requested */
  if( zColumnName==0 ){
................................................................................
    zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName,
        zColumnName);
    rc = SQLITE_ERROR;
  }
  sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
  sqlite3DbFree(db, zErrMsg);
  rc = sqlite3ApiExit(db, rc);

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

/*
** Sleep for a little while.  Return the amount of time slept.
*/







>
>
>
>
>
>
>
>
>
>
>







 







>







 







|









|









>

>
|
<
<



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







 







>







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
....
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
....
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687


3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
....
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
    Schema *pSchema = db->aDb[i].pSchema;
    if( pSchema ){
      for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
        Table *pTab = (Table *)sqliteHashData(p);
        if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
      }
    }
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    if( IsSharedSchema(db) && i!=1 ){
      VTable *pVTable;
      VTable *pNext;
      for(pVTable=db->aDb[i].pVTable; pVTable; pVTable=pNext){
        pNext = pVTable->pNext;
        sqlite3VtabUnlock(pVTable);
      }
      db->aDb[i].pVTable = 0;
    }
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
  }
  for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){
    Module *pMod = (Module *)sqliteHashData(p);
    if( pMod->pEpoTab ){
      sqlite3VtabDisconnect(db, pMod->pEpoTab);
    }
  }
................................................................................
  /* Close all database connections */
  for(j=0; j<db->nDb; j++){
    struct Db *pDb = &db->aDb[j];
    if( pDb->pBt ){
      sqlite3BtreeClose(pDb->pBt);
      pDb->pBt = 0;
      if( j!=1 ){
        sqlite3SchemaDisconnect(db, j, 0);
        pDb->pSchema = 0;
      }
    }
  }
  /* Clear the TEMP schema separately and last */
  if( db->aDb[1].pSchema ){
    sqlite3SchemaClear(db->aDb[1].pSchema);
................................................................................
  const char *zColumnName,    /* Column name */
  char const **pzDataType,    /* OUTPUT: Declared data type */
  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */
  int *pNotNull,              /* OUTPUT: True if NOT NULL constraint exists */
  int *pPrimaryKey,           /* OUTPUT: True if column part of PK */
  int *pAutoinc               /* OUTPUT: True if column is auto-increment */
){
  int rc = SQLITE_OK;
  char *zErrMsg = 0;
  Table *pTab = 0;
  Column *pCol = 0;
  int iCol = 0;
  char const *zDataType = 0;
  char const *zCollSeq = 0;
  int notnull = 0;
  int primarykey = 0;
  int autoinc = 0;
  int bUnlock;

#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif

  /* Ensure the database schema has been loaded */
  sqlite3_mutex_enter(db->mutex);
  bUnlock = sqlite3LockReusableSchema(db);
  sqlite3BtreeEnterAll(db);
  if( IsSharedSchema(db)==0 ){
    rc = sqlite3Init(db, &zErrMsg);


  }

  /* Locate the table in question */
  if( rc==SQLITE_OK ){
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    Parse sParse;                   /* Fake Parse object for FindTable */
    Parse *pSaved = db->pParse;
    memset(&sParse, 0, sizeof(sParse));
    db->pParse = &sParse;
#endif
    pTab = sqlite3FindTable(db, zTableName, zDbName);
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    sqlite3_free(sParse.zErrMsg);
    rc = sParse.rc;
    db->pParse = pSaved;
#endif
  }
  if( SQLITE_OK!=rc ) goto error_out;

  if( !pTab || pTab->pSelect ){
    pTab = 0;
    goto error_out;
  }

  /* Find the column for which info is requested */
  if( zColumnName==0 ){
................................................................................
    zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName,
        zColumnName);
    rc = SQLITE_ERROR;
  }
  sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
  sqlite3DbFree(db, zErrMsg);
  rc = sqlite3ApiExit(db, rc);
  sqlite3UnlockReusableSchema(db, bUnlock);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Sleep for a little while.  Return the amount of time slept.
*/

Changes to src/pragma.c.

465
466
467
468
469
470
471





472

473
474
475
476
477
478
479
....
1899
1900
1901
1902
1903
1904
1905
1906

1907
1908
1909
1910
1911
1912
1913
1914
1915

  /* Locate the pragma in the lookup table */
  pPragma = pragmaLocate(zLeft);
  if( pPragma==0 ) goto pragma_out;

  /* Make sure the database schema is loaded if the pragma requires that */
  if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){





    if( sqlite3ReadSchema(pParse) ) goto pragma_out;

  }

  /* Register the result column names for pragmas that return results */
  if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 
   && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0)
  ){
    setPragmaResultColumnNames(v, pPragma);
................................................................................
  ** the schema-version is potentially dangerous and may lead to program
  ** crashes or database corruption. Use with caution!
  **
  ** The user-version is not used internally by SQLite. It may be used by
  ** applications for any purpose.
  */
  case PragTyp_HEADER_VALUE: {
    int iCookie = pPragma->iArg;  /* Which cookie to read or write */

    sqlite3VdbeUsesBtree(v, iDb);
    if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){
      /* Write the specified cookie value */
      static const VdbeOpList setCookie[] = {
        { OP_Transaction,    0,  1,  0},    /* 0 */
        { OP_SetCookie,      0,  0,  0},    /* 1 */
      };
      VdbeOp *aOp;
      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));







>
>
>
>
>
|
>







 







|
>

|







465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
....
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922

  /* Locate the pragma in the lookup table */
  pPragma = pragmaLocate(zLeft);
  if( pPragma==0 ) goto pragma_out;

  /* Make sure the database schema is loaded if the pragma requires that */
  if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
    if( IsSharedSchema(db) && (zDb || (pPragma->mPragFlg & PragFlg_OneSchema)) ){
      assert( iDb>=0 && iDb<db->nDb );
      pParse->rc = sqlite3SchemaLoad(db, iDb, 0, &pParse->zErrMsg);
      if( pParse->rc ) goto pragma_out;
    }else{
      if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    }
  }

  /* Register the result column names for pragmas that return results */
  if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 
   && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0)
  ){
    setPragmaResultColumnNames(v, pPragma);
................................................................................
  ** the schema-version is potentially dangerous and may lead to program
  ** crashes or database corruption. Use with caution!
  **
  ** The user-version is not used internally by SQLite. It may be used by
  ** applications for any purpose.
  */
  case PragTyp_HEADER_VALUE: {
    int iCookie;                  /* Which cookie to read or write */
    iCookie = pPragma->iArg & PRAGMA_HEADER_VALUE_MASK;     
    sqlite3VdbeUsesBtree(v, iDb);
    if( zRight && (pPragma->iArg & PRAGMA_HEADER_VALUE_READONLY)==0 ){
      /* Write the specified cookie value */
      static const VdbeOpList setCookie[] = {
        { OP_Transaction,    0,  1,  0},    /* 0 */
        { OP_SetCookie,      0,  0,  0},    /* 1 */
      };
      VdbeOp *aOp;
      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));

Changes to src/pragma.h.

51
52
53
54
55
56
57
58
59
60
61
62







63
64
65
66
67
68
69
...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
...
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
...
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
#define PragTyp_LOCK_STATUS                   43
#define PragTyp_STATS                         44

/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
#define PragFlg_ReadOnly   0x08 /* Read-only HEADER_VALUE */
#define PragFlg_Result0    0x10 /* Acts as query when no argument */
#define PragFlg_Result1    0x20 /* Acts as query when has one argument */
#define PragFlg_SchemaOpt  0x40 /* Schema restricts name search if present */
#define PragFlg_SchemaReq  0x80 /* Schema required - "main" is default */








/* Names of columns for pragmas that return multi-column result
** or that return single-column results where the name of the
** result column is different from the name of the pragma
*/
static const char *const pragCName[] = {
  /*   0 */ "id",          /* Used by: foreign_key_list */
................................................................................
  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_APPLICATION_ID },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
 {/* zName:     */ "auto_vacuum",
  /* ePragTyp:  */ PragTyp_AUTO_VACUUM,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
 {/* zName:     */ "automatic_index",
  /* ePragTyp:  */ PragTyp_FLAG,
................................................................................
  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 50, 1,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "cache_size",
  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "cache_spill",
  /* ePragTyp:  */ PragTyp_CACHE_SPILL,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
................................................................................
  /* ePragFlg:  */ PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
 {/* zName:     */ "data_version",
  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
  /* ePragFlg:  */ PragFlg_ReadOnly|PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "database_list",
  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
  /* ColNames:  */ 41, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
 {/* zName:     */ "default_cache_size",
  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 49, 1,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "defer_foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
................................................................................
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 37, 4,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
 {/* zName:     */ "foreign_key_list",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 0, 8,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
................................................................................
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_ForeignKeys },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
 {/* zName:     */ "freelist_count",
  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
  /* ePragFlg:  */ PragFlg_ReadOnly|PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_FREE_PAGE_COUNT },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "full_column_names",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_FullColNames },
................................................................................
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_IgnoreChecks },
#endif
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
 {/* zName:     */ "incremental_vacuum",
  /* ePragTyp:  */ PragTyp_INCREMENTAL_VACUUM,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_NoColumns,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "index_info",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
................................................................................
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "journal_mode",
  /* ePragTyp:  */ PragTyp_JOURNAL_MODE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "journal_size_limit",
  /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
................................................................................
 {/* zName:     */ "locking_mode",
  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "max_page_count",
  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "mmap_size",
  /* ePragTyp:  */ PragTyp_MMAP_SIZE,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
................................................................................
  /* ePragTyp:  */ PragTyp_OPTIMIZE,
  /* ePragFlg:  */ PragFlg_Result1|PragFlg_NeedSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "page_count",
  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "page_size",
  /* ePragTyp:  */ PragTyp_PAGE_SIZE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
................................................................................
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
 {/* zName:     */ "stats",
  /* ePragTyp:  */ PragTyp_STATS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 27, 5,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "synchronous",
  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "table_info",
  /* ePragTyp:  */ PragTyp_TABLE_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
................................................................................
 {/* zName:     */ "wal_autocheckpoint",
  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "wal_checkpoint",
  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
  /* ePragFlg:  */ PragFlg_NeedSchema,
  /* ColNames:  */ 44, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "writable_schema",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
/* Number of pragmas: 67 on by default, 77 total. */







|




>
>
>
>
>
>
>







 







|







 







|







 







|

|




|






|







 







|







 







|

|







 







|







 







|







 







|







 







|







 







|






|







 







|












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
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
...
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
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
...
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
...
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
#define PragTyp_LOCK_STATUS                   43
#define PragTyp_STATS                         44

/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
#define PragFlg_OneSchema  0x08 /* Only a single schema required */
#define PragFlg_Result0    0x10 /* Acts as query when no argument */
#define PragFlg_Result1    0x20 /* Acts as query when has one argument */
#define PragFlg_SchemaOpt  0x40 /* Schema restricts name search if present */
#define PragFlg_SchemaReq  0x80 /* Schema required - "main" is default */

/* For PragTyp_HEADER_VALUE pragmas the Pragma.iArg value is set
** to the index of the header field to access (always 10 or less).
** Ored with HEADER_VALUE_READONLY if the field is read only. */
#define PRAGMA_HEADER_VALUE_READONLY 0x0100
#define PRAGMA_HEADER_VALUE_MASK 0x00FF


/* Names of columns for pragmas that return multi-column result
** or that return single-column results where the name of the
** result column is different from the name of the pragma
*/
static const char *const pragCName[] = {
  /*   0 */ "id",          /* Used by: foreign_key_list */
................................................................................
  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_APPLICATION_ID },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
 {/* zName:     */ "auto_vacuum",
  /* ePragTyp:  */ PragTyp_AUTO_VACUUM,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
 {/* zName:     */ "automatic_index",
  /* ePragTyp:  */ PragTyp_FLAG,
................................................................................
  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 50, 1,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "cache_size",
  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "cache_spill",
  /* ePragTyp:  */ PragTyp_CACHE_SPILL,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
................................................................................
  /* ePragFlg:  */ PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
 {/* zName:     */ "data_version",
  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_DATA_VERSION|PRAGMA_HEADER_VALUE_READONLY },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "database_list",
  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_OneSchema,
  /* ColNames:  */ 41, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
 {/* zName:     */ "default_cache_size",
  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
  /* ColNames:  */ 49, 1,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "defer_foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
................................................................................
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 37, 4,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
 {/* zName:     */ "foreign_key_list",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt|PragFlg_OneSchema,
  /* ColNames:  */ 0, 8,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
................................................................................
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_ForeignKeys },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
 {/* zName:     */ "freelist_count",
  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_FREE_PAGE_COUNT|PRAGMA_HEADER_VALUE_READONLY },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "full_column_names",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_FullColNames },
................................................................................
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_IgnoreChecks },
#endif
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
 {/* zName:     */ "incremental_vacuum",
  /* ePragTyp:  */ PragTyp_INCREMENTAL_VACUUM,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_NoColumns|PragFlg_OneSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "index_info",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
................................................................................
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "journal_mode",
  /* ePragTyp:  */ PragTyp_JOURNAL_MODE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "journal_size_limit",
  /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
................................................................................
 {/* zName:     */ "locking_mode",
  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "max_page_count",
  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "mmap_size",
  /* ePragTyp:  */ PragTyp_MMAP_SIZE,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
................................................................................
  /* ePragTyp:  */ PragTyp_OPTIMIZE,
  /* ePragFlg:  */ PragFlg_Result1|PragFlg_NeedSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "page_count",
  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "page_size",
  /* ePragTyp:  */ PragTyp_PAGE_SIZE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
................................................................................
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
 {/* zName:     */ "stats",
  /* ePragTyp:  */ PragTyp_STATS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema,
  /* ColNames:  */ 27, 5,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "synchronous",
  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "table_info",
  /* ePragTyp:  */ PragTyp_TABLE_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
................................................................................
 {/* zName:     */ "wal_autocheckpoint",
  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "wal_checkpoint",
  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_OneSchema,
  /* ColNames:  */ 44, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "writable_schema",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
/* Number of pragmas: 67 on by default, 77 total. */

Changes to src/prepare.c.

30
31
32
33
34
35
36





37
38
39
40
41
42
43
44
45
46






















47
48
49
50
51
52
53
..
55
56
57
58
59
60
61









62
63
64
65
66
67
68
...
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
...
163
164
165
166
167
168
169






170
171
172
173
174
175
176
...
190
191
192
193
194
195
196
197
198
199


















200
201
202
203
204
205
206
...
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
...
378
379
380
381
382
383
384




385
386
387
388
389
390
391
...
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
...
475
476
477
478
479
480
481




482
483
484
485
486
487
488
...
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
748
749
750
751
752
753
  }else if( pData->pzErrMsg[0]!=0 ){
    /* A error message has already been generated.  Do not overwrite it */
  }else if( pData->mInitFlags & INITFLAG_AlterTable ){
    *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
    pData->rc = SQLITE_ERROR;
  }else if( db->flags & SQLITE_WriteSchema ){
    pData->rc = SQLITE_CORRUPT_BKPT;





  }else{
    char *z;
    if( zObj==0 ) zObj = "?";
    z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
    if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
    *pData->pzErrMsg = z;
    pData->rc = SQLITE_CORRUPT_BKPT;
  }
}























/*
** Check to see if any sibling index (another index on the same table)
** of pIndex has the same root page number, and if it does, return true.
** This would indicate a corrupt schema.
*/
int sqlite3IndexHasDuplicateRootPage(Index *pIndex){
  Index *p;
................................................................................
    if( p->tnum==pIndex->tnum && p!=pIndex ) return 1;
  }
  return 0;
}

/* forward declaration */
static int sqlite3Prepare(









  sqlite3 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
  Vdbe *pReprepare,         /* VM being reprepared */
  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
................................................................................
      if( sqlite3Config.bExtraSchemaChecks ){
        corruptSchema(pData, argv[1], "invalid rootpage");
      }
    }
    db->init.orphanTrigger = 0;
    db->init.azInit = argv;
    pStmt = 0;



    TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);

    rc = db->errCode;
    assert( (rc&0xFF)==(rcp&0xFF) );
    db->init.iDb = saved_iDb;
    /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
    if( SQLITE_OK!=rc ){
      if( db->init.orphanTrigger ){
        assert( iDb==1 );
      }else{
        if( rc > pData->rc ) pData->rc = rc;
        if( rc==SQLITE_NOMEM ){
          sqlite3OomFault(db);
        }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){





          corruptSchema(pData, argv[1], sqlite3_errmsg(db));
        }
      }
    }
    sqlite3_finalize(pStmt);
  }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
    corruptSchema(pData, argv[1], 0);
................................................................................
     || sqlite3IndexHasDuplicateRootPage(pIndex)
    ){
      if( sqlite3Config.bExtraSchemaChecks ){
        corruptSchema(pData, argv[1], "invalid rootpage");
      }
    }
  }






  return 0;
}

/*
** Attempt to read the database schema and initialize internal
** data structures for a single database file.  The index of the
** database file is given by iDb.  iDb==0 is used for the main
................................................................................
  InitData initData;
  const char *zSchemaTabName;
  int openedTransaction = 0;
  int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed);

  assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pSchema );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );



















  db->init.busy = 1;

  /* Construct the in-memory representation schema tables (sqlite_schema or
  ** sqlite_temp_schema) by invoking the parser directly.  The appropriate
  ** table name will be inserted automatically by the parser so we can just
  ** use the abbreviation "x" here.  The parser will also automatically tag
................................................................................
  azArg[5] = 0;
  initData.db = db;
  initData.iDb = iDb;
  initData.rc = SQLITE_OK;
  initData.pzErrMsg = pzErrMsg;
  initData.mInitFlags = mFlags;
  initData.nInitRow = 0;

  initData.mxPage = 0;
  sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
  db->mDbFlags &= mask;
  if( initData.rc ){
    rc = initData.rc;
    goto error_out;
  }

  /* Create a cursor to hold the database open
  */
  pDb = &db->aDb[iDb];
  if( pDb->pBt==0 ){
    assert( iDb==1 );
    DbSetProperty(db, 1, DB_SchemaLoaded);
    rc = SQLITE_OK;
    goto error_out;
  }

................................................................................
    ** of the schema was loaded before the error occurred. The primary
    ** purpose of this is to allow access to the sqlite_schema table
    ** even when its contents have been corrupted.
    */
    DbSetProperty(db, iDb, DB_SchemaLoaded);
    rc = SQLITE_OK;
  }





  /* Jump here for an error that occurs after successfully allocating
  ** curMain and calling sqlite3BtreeEnter(). For an error that occurs
  ** before that point, jump to error_out.
  */
initone_error_out:
  if( openedTransaction ){
................................................................................
    }
    sqlite3ResetOneSchema(db, iDb);
  }
  db->init.busy = 0;
  return rc;
}






























/*
** Initialize all database files - the main database file, the file
** used to store temporary tables, and any additional database files
** created using ATTACH statements.  Return a success code.  If an
** error occurs, write an error message into *pzErrMsg.
**
** After a database is initialized, the DB_SchemaLoaded bit is set
** bit is set in the flags field of the Db structure. 
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){


  int i, rc;
  int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);


  
  assert( sqlite3_mutex_held(db->mutex) );
  assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
  assert( db->init.busy==0 );
  ENC(db) = SCHEMA_ENC(db);
  assert( db->nDb>0 );
  /* Do the main schema first */
  if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
    rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
    if( rc ) return rc;
  }
  /* All other schemas after the main schema. The "temp" schema must be last */
  for(i=db->nDb-1; i>0; i--){
    assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
    if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
      rc = sqlite3InitOne(db, i, pzErrMsg, 0);
      if( rc ) return rc;
    }
  }
  if( commit_internal ){
    sqlite3CommitInternalChanges(db);
  }

  return SQLITE_OK;
}

/*
** This routine is a no-op if the database schema is already initialized.
** Otherwise, the schema is loaded. An error code is returned.
*/
int sqlite3ReadSchema(Parse *pParse){
  int rc = SQLITE_OK;
  sqlite3 *db = pParse->db;
  assert( sqlite3_mutex_held(db->mutex) );
  if( !db->init.busy ){

    rc = sqlite3Init(db, &pParse->zErrMsg);
    if( rc!=SQLITE_OK ){
      pParse->rc = rc;
      pParse->nErr++;
    }else if( db->noSharedCache ){
      db->mDbFlags |= DBFLAG_SchemaKnownOk;
    }
  }
  return rc;
}


................................................................................

  assert( pParse->checkSchema );
  assert( sqlite3_mutex_held(db->mutex) );
  for(iDb=0; iDb<db->nDb; iDb++){
    int openedTransaction = 0;         /* True if a transaction is opened */
    Btree *pBt = db->aDb[iDb].pBt;     /* Btree database to read cookie from */
    if( pBt==0 ) continue;





    /* If there is not already a read-only (or read-write) transaction opened
    ** on the b-tree database, open one now. If a transaction is opened, it 
    ** will be closed immediately after reading the meta-value. */
    if( !sqlite3BtreeIsInReadTrans(pBt) ){
      rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
      if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
................................................................................
  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
  Vdbe *pOld,               /* VM being reprepared */
  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
){
  int rc;
  int cnt = 0;


#ifdef SQLITE_ENABLE_API_ARMOR
  if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
#endif
  *ppStmt = 0;
  if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
    return SQLITE_MISUSE_BKPT;
  }
  sqlite3_mutex_enter(db->mutex);

  sqlite3BtreeEnterAll(db);
  do{
    /* Make multiple attempts to compile the SQL, until it either succeeds
    ** or encounters a permanent error.  A schema problem after one schema
    ** reset is considered a permanent error. */
    rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
    assert( rc==SQLITE_OK || *ppStmt==0 );
  }while( rc==SQLITE_ERROR_RETRY
       || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );

  sqlite3BtreeLeaveAll(db);



  rc = sqlite3ApiExit(db, rc);
  assert( (rc&db->errMask)==rc );
  sqlite3_mutex_leave(db->mutex);
  return rc;
}









>
>
>
>
>










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







 







>
>
>
>
>
>
>
>
>







 







>
>
>

>











|
>
>
>
>
>







 







>
>
>
>
>
>







 







|


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







 







>










<







 







>
>
>
>







 







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










>
>
|

>
>









<


|



<


|


>
|











>




|







 







>
>
>
>







 







>









>









>

>
>
>







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
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
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
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
...
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
...
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
...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
...
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
...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
...
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  }else if( pData->pzErrMsg[0]!=0 ){
    /* A error message has already been generated.  Do not overwrite it */
  }else if( pData->mInitFlags & INITFLAG_AlterTable ){
    *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
    pData->rc = SQLITE_ERROR;
  }else if( db->flags & SQLITE_WriteSchema ){
    pData->rc = SQLITE_CORRUPT_BKPT;
  }else if( IsSharedSchema(db) 
         && 0==sqlite3StrNICmp(zExtra, "malformed database schema", 17)
  ){
    pData->rc = SQLITE_CORRUPT_BKPT;
    *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
  }else{
    char *z;
    if( zObj==0 ) zObj = "?";
    z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
    if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
    *pData->pzErrMsg = z;
    pData->rc = SQLITE_CORRUPT_BKPT;
  }
}

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
/*
** Update the Schema.cksum checksum to account for the database object
** specified by the three arguments following the first.
*/
static void schemaUpdateChecksum(
  InitData *pData,                /* Schema parse context */
  const char *zName,              /* Name of new database object */
  const char *zRoot,              /* Root page of new database object */
  const char *zSql                /* SQL used to create new database object */
){
  int i;
  u64 cksum = pData->cksum;
  if( zName ){
    for(i=0; zName[i]; i++) cksum += (cksum<<3) + zName[i];
  }
  if( zRoot ) for(i=0; zRoot[i]; i++) cksum += (cksum<<3) + zRoot[i];
  if( zSql ) for(i=0; zSql[i]; i++) cksum += (cksum<<3) + zSql[i];
  pData->cksum = cksum;
}
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */

/*
** Check to see if any sibling index (another index on the same table)
** of pIndex has the same root page number, and if it does, return true.
** This would indicate a corrupt schema.
*/
int sqlite3IndexHasDuplicateRootPage(Index *pIndex){
  Index *p;
................................................................................
    if( p->tnum==pIndex->tnum && p!=pIndex ) return 1;
  }
  return 0;
}

/* forward declaration */
static int sqlite3Prepare(
  sqlite3 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
  Vdbe *pReprepare,         /* VM being reprepared */
  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
);
static int sqlite3LockAndPrepare(
  sqlite3 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
  Vdbe *pReprepare,         /* VM being reprepared */
  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
................................................................................
      if( sqlite3Config.bExtraSchemaChecks ){
        corruptSchema(pData, argv[1], "invalid rootpage");
      }
    }
    db->init.orphanTrigger = 0;
    db->init.azInit = argv;
    pStmt = 0;
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    TESTONLY(rcp = ) sqlite3LockAndPrepare(db, argv[4], -1, 0, 0, &pStmt, 0);
#else
    TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
#endif
    rc = db->errCode;
    assert( (rc&0xFF)==(rcp&0xFF) );
    db->init.iDb = saved_iDb;
    /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
    if( SQLITE_OK!=rc ){
      if( db->init.orphanTrigger ){
        assert( iDb==1 );
      }else{
        if( rc > pData->rc ) pData->rc = rc;
        if( rc==SQLITE_NOMEM ){
          sqlite3OomFault(db);
        }else if( rc!=SQLITE_INTERRUPT 
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
               && (rc&0xFF)!=SQLITE_LOCKED 
               && (rc&0xFF)!=SQLITE_IOERR
#endif
        ){
          corruptSchema(pData, argv[1], sqlite3_errmsg(db));
        }
      }
    }
    sqlite3_finalize(pStmt);
  }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
    corruptSchema(pData, argv[1], 0);
................................................................................
     || sqlite3IndexHasDuplicateRootPage(pIndex)
    ){
      if( sqlite3Config.bExtraSchemaChecks ){
        corruptSchema(pData, argv[1], "invalid rootpage");
      }
    }
  }

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  if( IsSharedSchema(db) && iDb!=1 ){
    schemaUpdateChecksum(pData, argv[0], argv[1], argv[2]);
  }
#endif
  return 0;
}

/*
** Attempt to read the database schema and initialize internal
** data structures for a single database file.  The index of the
** database file is given by iDb.  iDb==0 is used for the main
................................................................................
  InitData initData;
  const char *zSchemaTabName;
  int openedTransaction = 0;
  int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed);

  assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pSchema || (IsSharedSchema(db) && iDb!=1) );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );

  pDb = &db->aDb[iDb];
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  assert( pDb->pSPool==0 || IsSharedSchema(db) );
  if( pDb->pSPool ){
    /* See if there is a free schema object in the schema-pool. If not,
    ** disconnect from said schema pool and continue. This function will
    ** connect to a (possibly different) schema-pool before returning. */
    Schema *pNew = sqlite3SchemaExtract(pDb->pSPool);
    if( pNew ){
      pDb->pSchema = pNew;
      return SQLITE_OK;
    }
    rc = sqlite3SchemaDisconnect(db, iDb, 1);
    if( rc!=SQLITE_OK ) goto error_out;
    assert( pDb->pSchema && pDb->pSPool==0 );
  }
#endif

  db->init.busy = 1;

  /* Construct the in-memory representation schema tables (sqlite_schema or
  ** sqlite_temp_schema) by invoking the parser directly.  The appropriate
  ** table name will be inserted automatically by the parser so we can just
  ** use the abbreviation "x" here.  The parser will also automatically tag
................................................................................
  azArg[5] = 0;
  initData.db = db;
  initData.iDb = iDb;
  initData.rc = SQLITE_OK;
  initData.pzErrMsg = pzErrMsg;
  initData.mInitFlags = mFlags;
  initData.nInitRow = 0;
  initData.cksum = 0;
  initData.mxPage = 0;
  sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
  db->mDbFlags &= mask;
  if( initData.rc ){
    rc = initData.rc;
    goto error_out;
  }

  /* Create a cursor to hold the database open
  */

  if( pDb->pBt==0 ){
    assert( iDb==1 );
    DbSetProperty(db, 1, DB_SchemaLoaded);
    rc = SQLITE_OK;
    goto error_out;
  }

................................................................................
    ** of the schema was loaded before the error occurred. The primary
    ** purpose of this is to allow access to the sqlite_schema table
    ** even when its contents have been corrupted.
    */
    DbSetProperty(db, iDb, DB_SchemaLoaded);
    rc = SQLITE_OK;
  }

  if( rc==SQLITE_OK && iDb!=1 && IsSharedSchema(db) ){
    rc = sqlite3SchemaConnect(db, iDb, initData.cksum);
  }

  /* Jump here for an error that occurs after successfully allocating
  ** curMain and calling sqlite3BtreeEnter(). For an error that occurs
  ** before that point, jump to error_out.
  */
initone_error_out:
  if( openedTransaction ){
................................................................................
    }
    sqlite3ResetOneSchema(db, iDb);
  }
  db->init.busy = 0;
  return rc;
}


#ifdef SQLITE_ENABLE_SHARED_SCHEMA
/*
** If this is a SHARED_SCHEMA connection and the DBFLAG_SchemaInUse flag
** is not currently set, set it and return non-zero. Otherwise, return 0.
*/
int sqlite3LockReusableSchema(sqlite3 *db){
  if( IsSharedSchema(db) && (db->mDbFlags & DBFLAG_SchemaInuse)==0 ){
    db->mDbFlags |= DBFLAG_SchemaInuse;
    return 1;
  }
  return 0;
}
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
/*
** This function is a no-op for non-SHARED_SCHEMA connections, or if bRelease
** is zero. Otherwise, clear the DBFLAG_SchemaInuse flag and release all
** schema references currently held.
*/
void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease){
  if( bRelease ){
    db->mDbFlags &= ~DBFLAG_SchemaInuse;
    sqlite3SchemaReleaseAll(db);
  }
}
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */

/*
** Initialize all database files - the main database file, the file
** used to store temporary tables, and any additional database files
** created using ATTACH statements.  Return a success code.  If an
** error occurs, write an error message into *pzErrMsg.
**
** After a database is initialized, the DB_SchemaLoaded bit is set
** bit is set in the flags field of the Db structure. 
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
  int rc = SQLITE_OK;
  int bReleaseSchema;
  int i;
  int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);

  bReleaseSchema = sqlite3LockReusableSchema(db);
  
  assert( sqlite3_mutex_held(db->mutex) );
  assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
  assert( db->init.busy==0 );
  ENC(db) = SCHEMA_ENC(db);
  assert( db->nDb>0 );
  /* Do the main schema first */
  if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
    rc = sqlite3InitOne(db, 0, pzErrMsg, 0);

  }
  /* All other schemas after the main schema. The "temp" schema must be last */
  for(i=db->nDb-1; rc==SQLITE_OK && i>0; i--){
    assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
    if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
      rc = sqlite3InitOne(db, i, pzErrMsg, 0);

    }
  }
  if( rc==SQLITE_OK && commit_internal ){
    sqlite3CommitInternalChanges(db);
  }
  sqlite3UnlockReusableSchema(db, bReleaseSchema);
  return rc;
}

/*
** This routine is a no-op if the database schema is already initialized.
** Otherwise, the schema is loaded. An error code is returned.
*/
int sqlite3ReadSchema(Parse *pParse){
  int rc = SQLITE_OK;
  sqlite3 *db = pParse->db;
  assert( sqlite3_mutex_held(db->mutex) );
  if( !db->init.busy ){
    db->mDbFlags |= DBFLAG_FreeSchema;      /* For sharable-schema mode */
    rc = sqlite3Init(db, &pParse->zErrMsg);
    if( rc!=SQLITE_OK ){
      pParse->rc = rc;
      pParse->nErr++;
    }else if( db->noSharedCache && !IsSharedSchema(db) ){
      db->mDbFlags |= DBFLAG_SchemaKnownOk;
    }
  }
  return rc;
}


................................................................................

  assert( pParse->checkSchema );
  assert( sqlite3_mutex_held(db->mutex) );
  for(iDb=0; iDb<db->nDb; iDb++){
    int openedTransaction = 0;         /* True if a transaction is opened */
    Btree *pBt = db->aDb[iDb].pBt;     /* Btree database to read cookie from */
    if( pBt==0 ) continue;

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    if( IsSharedSchema(db) && iDb!=1 && db->aDb[iDb].pSPool==0 ) continue;
#endif

    /* If there is not already a read-only (or read-write) transaction opened
    ** on the b-tree database, open one now. If a transaction is opened, it 
    ** will be closed immediately after reading the meta-value. */
    if( !sqlite3BtreeIsInReadTrans(pBt) ){
      rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
      if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
................................................................................
  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
  Vdbe *pOld,               /* VM being reprepared */
  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
){
  int rc;
  int cnt = 0;
  int bReleaseSchema = 0;

#ifdef SQLITE_ENABLE_API_ARMOR
  if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
#endif
  *ppStmt = 0;
  if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
    return SQLITE_MISUSE_BKPT;
  }
  sqlite3_mutex_enter(db->mutex);
  bReleaseSchema = sqlite3LockReusableSchema(db);
  sqlite3BtreeEnterAll(db);
  do{
    /* Make multiple attempts to compile the SQL, until it either succeeds
    ** or encounters a permanent error.  A schema problem after one schema
    ** reset is considered a permanent error. */
    rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
    assert( rc==SQLITE_OK || *ppStmt==0 );
  }while( rc==SQLITE_ERROR_RETRY
       || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );

  sqlite3BtreeLeaveAll(db);

  sqlite3UnlockReusableSchema(db, bReleaseSchema);

  rc = sqlite3ApiExit(db, rc);
  assert( (rc&db->errMask)==rc );
  sqlite3_mutex_leave(db->mutex);
  return rc;
}


Changes to src/shell.c.in.

1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162

1163
1164
1165
1166
1167
1168
1169
....
4042
4043
4044
4045
4046
4047
4048






4049
4050
4051
4052
4053
4054
4055
....
4559
4560
4561
4562
4563
4564
4565





4566
4567
4568
4569
4570
4571
4572
....
6750
6751
6752
6753
6754
6755
6756







































































































































































































































6757
6758
6759
6760
6761
6762
6763
....
8641
8642
8643
8644
8645
8646
8647


8648
8649
8650
8651
8652
8653
8654
....
9624
9625
9626
9627
9628
9629
9630







9631
9632
9633
9634
9635
9636
9637
.....
10927
10928
10929
10930
10931
10932
10933


10934
10935
10936
10937
10938
10939
10940
.....
11040
11041
11042
11043
11044
11045
11046


11047
11048
11049
11050
11051
11052
11053
#define AUTOEQP_off      0           /* Automatic EXPLAIN QUERY PLAN is off */
#define AUTOEQP_on       1           /* Automatic EQP is on */
#define AUTOEQP_trigger  2           /* On and also show plans for triggers */
#define AUTOEQP_full     3           /* Show full EXPLAIN */

/* Allowed values for ShellState.openMode
*/
#define SHELL_OPEN_UNSPEC      0      /* No open-mode specified */
#define SHELL_OPEN_NORMAL      1      /* Normal database file */
#define SHELL_OPEN_APPENDVFS   2      /* Use appendvfs */
#define SHELL_OPEN_ZIPFILE     3      /* Use the zipfile virtual table */
#define SHELL_OPEN_READONLY    4      /* Open a normal database read-only */
#define SHELL_OPEN_DESERIALIZE 5      /* Open using sqlite3_deserialize() */
#define SHELL_OPEN_HEXDB       6      /* Use "dbtotxt" output as data source */


/* Allowed values for ShellState.eTraceType
*/
#define SHELL_TRACE_PLAIN      0      /* Show input SQL text */
#define SHELL_TRACE_EXPANDED   1      /* Show expanded SQL text */
#define SHELL_TRACE_NORMALIZED 2      /* Show normalized SQL text */

................................................................................
  "    Options:",
  "      --schema              Also hash the sqlite_schema table",
  "      --sha3-224            Use the sha3-224 algorithm",
  "      --sha3-256            Use the sha3-256 algorithm (default)",
  "      --sha3-384            Use the sha3-384 algorithm",
  "      --sha3-512            Use the sha3-512 algorithm",
  "    Any other argument is a LIKE pattern for tables to hash",






#ifndef SQLITE_NOHAVE_SYSTEM
  ".shell CMD ARGS...       Run CMD ARGS... in a system shell",
#endif
  ".show                    Show the current values for various settings",
  ".stats ?on|off?          Show stats or turn stats on or off",
#ifndef SQLITE_NOHAVE_SYSTEM
  ".system CMD ARGS...      Run CMD ARGS... in a system shell",
................................................................................
        sqlite3_open(":memory:", &p->db);
        break;
      }
      case SHELL_OPEN_READONLY: {
        sqlite3_open_v2(p->zDbFilename, &p->db,
            SQLITE_OPEN_READONLY|p->openFlags, 0);
        break;





      }
      case SHELL_OPEN_UNSPEC:
      case SHELL_OPEN_NORMAL: {
        sqlite3_open_v2(p->zDbFilename, &p->db,
           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
        break;
      }
................................................................................
    va_end(ap);
    if( z==0 ){
      *pRc = SQLITE_NOMEM;
    }
  }
  return z;
}








































































































































































































































/*
** When running the ".recover" command, each output table, and the special
** orphaned row table if it is required, is represented by an instance
** of the following struct.
*/
typedef struct RecoverTable RecoverTable;
................................................................................
      }else if( optionMatch(z, "zip") ){
        p->openMode = SHELL_OPEN_ZIPFILE;
#endif
      }else if( optionMatch(z, "append") ){
        p->openMode = SHELL_OPEN_APPENDVFS;
      }else if( optionMatch(z, "readonly") ){
        p->openMode = SHELL_OPEN_READONLY;


      }else if( optionMatch(z, "nofollow") ){
        p->openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifdef SQLITE_ENABLE_DESERIALIZE
      }else if( optionMatch(z, "deserialize") ){
        p->openMode = SHELL_OPEN_DESERIALIZE;
      }else if( optionMatch(z, "hexdb") ){
        p->openMode = SHELL_OPEN_HEXDB;
................................................................................
    if( bDebug ){
      utf8_printf(p->out, "%s\n", zSql);
    }else{
      shell_exec(p, zSql, 0);
    }
    sqlite3_free(zSql);
  }else








#ifndef SQLITE_NOHAVE_SYSTEM
  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
    int i, x;
................................................................................
    }else if( strcmp(z,"-deserialize")==0 ){
      data.openMode = SHELL_OPEN_DESERIALIZE;
    }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
      data.szMax = integerValue(argv[++i]);
#endif
    }else if( strcmp(z,"-readonly")==0 ){
      data.openMode = SHELL_OPEN_READONLY;


    }else if( strcmp(z,"-nofollow")==0 ){
      data.openFlags = SQLITE_OPEN_NOFOLLOW;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    }else if( strncmp(z, "-A",2)==0 ){
      /* All remaining command-line arguments are passed to the ".archive"
      ** command, so ignore them */
      break;
................................................................................
    }else if( strcmp(z,"-deserialize")==0 ){
      data.openMode = SHELL_OPEN_DESERIALIZE;
    }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
      data.szMax = integerValue(argv[++i]);
#endif
    }else if( strcmp(z,"-readonly")==0 ){
      data.openMode = SHELL_OPEN_READONLY;


    }else if( strcmp(z,"-nofollow")==0 ){
      data.openFlags |= SQLITE_OPEN_NOFOLLOW;
    }else if( strcmp(z,"-ascii")==0 ){
      data.mode = MODE_Ascii;
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
                       SEP_Unit);
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,







|
|
|
|
|
|
|
>







 







>
>
>
>
>
>







 







>
>
>
>
>







 







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







 







>
>







 







>
>
>
>
>
>
>







 







>
>







 







>
>







1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
....
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
....
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
....
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
6775
6776
6777
6778
6779
6780
6781
6782
6783
6784
6785
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
6877
6878
6879
6880
6881
6882
6883
6884
6885
6886
6887
6888
6889
6890
6891
6892
6893
6894
6895
6896
6897
6898
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912
6913
6914
6915
6916
6917
6918
6919
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
6937
6938
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
....
8884
8885
8886
8887
8888
8889
8890
8891
8892
8893
8894
8895
8896
8897
8898
8899
....
9869
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887
9888
9889
.....
11179
11180
11181
11182
11183
11184
11185
11186
11187
11188
11189
11190
11191
11192
11193
11194
.....
11294
11295
11296
11297
11298
11299
11300
11301
11302
11303
11304
11305
11306
11307
11308
11309
#define AUTOEQP_off      0           /* Automatic EXPLAIN QUERY PLAN is off */
#define AUTOEQP_on       1           /* Automatic EQP is on */
#define AUTOEQP_trigger  2           /* On and also show plans for triggers */
#define AUTOEQP_full     3           /* Show full EXPLAIN */

/* Allowed values for ShellState.openMode
*/
#define SHELL_OPEN_UNSPEC       0     /* No open-mode specified */
#define SHELL_OPEN_NORMAL       1     /* Normal database file */
#define SHELL_OPEN_APPENDVFS    2     /* Use appendvfs */
#define SHELL_OPEN_ZIPFILE      3     /* Use the zipfile virtual table */
#define SHELL_OPEN_READONLY     4     /* Open a normal database read-only */
#define SHELL_OPEN_DESERIALIZE  5     /* Open using sqlite3_deserialize() */
#define SHELL_OPEN_HEXDB        6     /* Use "dbtotxt" output as data source */
#define SHELL_OPEN_SHAREDSCHEMA 7     /* Open for schema reuse */

/* Allowed values for ShellState.eTraceType
*/
#define SHELL_TRACE_PLAIN      0      /* Show input SQL text */
#define SHELL_TRACE_EXPANDED   1      /* Show expanded SQL text */
#define SHELL_TRACE_NORMALIZED 2      /* Show normalized SQL text */

................................................................................
  "    Options:",
  "      --schema              Also hash the sqlite_schema table",
  "      --sha3-224            Use the sha3-224 algorithm",
  "      --sha3-256            Use the sha3-256 algorithm (default)",
  "      --sha3-384            Use the sha3-384 algorithm",
  "      --sha3-512            Use the sha3-512 algorithm",
  "    Any other argument is a LIKE pattern for tables to hash",
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
  ".shared-schema CMD DB1 DB2 ...",
  "    Commands:",
  "       check                Determine if DB1, DB2, etc have identical schemas",
  "       fix                  Attempt to make DB1, DB2, etc compatible",
#endif
#ifndef SQLITE_NOHAVE_SYSTEM
  ".shell CMD ARGS...       Run CMD ARGS... in a system shell",
#endif
  ".show                    Show the current values for various settings",
  ".stats ?on|off?          Show stats or turn stats on or off",
#ifndef SQLITE_NOHAVE_SYSTEM
  ".system CMD ARGS...      Run CMD ARGS... in a system shell",
................................................................................
        sqlite3_open(":memory:", &p->db);
        break;
      }
      case SHELL_OPEN_READONLY: {
        sqlite3_open_v2(p->zDbFilename, &p->db,
            SQLITE_OPEN_READONLY|p->openFlags, 0);
        break;
      }
      case SHELL_OPEN_SHAREDSCHEMA: {
        sqlite3_open_v2(p->zDbFilename, &p->db,
          SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SHARED_SCHEMA,0);
        break;
      }
      case SHELL_OPEN_UNSPEC:
      case SHELL_OPEN_NORMAL: {
        sqlite3_open_v2(p->zDbFilename, &p->db,
           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
        break;
      }
................................................................................
    va_end(ap);
    if( z==0 ){
      *pRc = SQLITE_NOMEM;
    }
  }
  return z;
}
static int sharedSchemaFix(ShellState *pState, const char *zDb, int eFix){
  int rc = SQLITE_OK;
  i64 iLast = 0;
  int iCookie = 0;
  int iAutoVacuum = 0;
  sqlite3_stmt *pStmt = 0;

  shellExecPrintf(pState->db, &rc, "ATTACH '%q' AS _shared_schema_tmp", zDb);
  shellExecPrintf(pState->db, &rc, "PRAGMA writable_schema = 1");
  shellExecPrintf(pState->db, &rc, "BEGIN");
  shellPreparePrintf(pState->db, &rc, &pStmt, 
      "SELECT max(rowid) FROM _shared_schema_tmp.sqlite_master"
  );
  sqlite3_step(pStmt);
  iLast = sqlite3_column_int64(pStmt, 0);
  shellFinalize(&rc, pStmt);
  shellPreparePrintf(pState->db, &rc, &pStmt,
      "INSERT INTO _shared_schema_tmp.sqlite_master SELECT "
      "  type, name, tbl_name, ("
      "    SELECT rootpage FROM _shared_schema_tmp.sqlite_master WHERE "
      "      type IS o.type AND name IS o.name AND rowid<=?"
      "  ), sql FROM main.sqlite_master AS o"
  );
  sqlite3_bind_int64(pStmt, 1, iLast);
  sqlite3_step(pStmt);
  shellFinalize(&rc, pStmt);

  shellExecPrintf(pState->db, &rc,
      "DELETE FROM _shared_schema_tmp.sqlite_master WHERE rowid<=%lld",
      iLast
  );
  shellExecPrintf(pState->db, &rc, "COMMIT");
  sqlite3_exec(pState->db, "PRAGMA writable_schema = 0", 0, 0, 0);

  /* Copy the auto-vacuum setting from main to the target db */
  shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA main.auto_vacuum");
  sqlite3_step(pStmt);
  iAutoVacuum = sqlite3_column_int(pStmt, 0);
  shellFinalize(&rc, pStmt);
  shellExecPrintf(pState->db, &rc, 
      "PRAGMA _shared_schema_tmp.auto_vacuum = %d", iAutoVacuum
  );

  /* Vacuum the db in order to standardize the rootpage numbers. */
  shellExecPrintf(pState->db, &rc, "VACUUM _shared_schema_tmp");

  /* Set the schema-cookie value to the same as database "main" */
  shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA main.schema_version");
  sqlite3_step(pStmt);
  iCookie = sqlite3_column_int(pStmt, 0);
  shellFinalize(&rc, pStmt);
  shellExecPrintf(pState->db, &rc, 
      "PRAGMA _shared_schema_tmp.schema_version = %d", iCookie
  );

  sqlite3_exec(pState->db, "DETACH _shared_schema_tmp", 0, 0, 0);
  return rc;
}

static int sharedSchemaCheck(ShellState *pState, const char *zDb, int *peFix){
  int rc = SQLITE_OK;
  int bFailed = 0;
  sqlite3_stmt *pStmt = 0;

  if( peFix ) *peFix = 0;
  shellExecPrintf(pState->db, &rc, "ATTACH '%q' AS _shared_schema_tmp", zDb);

  /* Check if this database has the same set of objects as the current db */
  shellPreparePrintf(pState->db, &rc, &pStmt, 
    "SELECT type, name FROM _shared_schema_tmp.sqlite_master AS o "
    "WHERE NOT EXISTS ("
    "  SELECT 1 FROM main.sqlite_master "
    "    WHERE name IS o.name AND type IS o.type"
    ")"
    " UNION ALL "
    "SELECT type, name FROM main.sqlite_master AS o "
    "WHERE NOT EXISTS ("
    "  SELECT 1 FROM _shared_schema_tmp.sqlite_master "
    "    WHERE name IS o.name AND type IS o.type"
    ")"
  );
  if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    utf8_printf(pState->out, "%s is NOT compatible (objects)\n", zDb);
    bFailed = 1;
  }
  shellFinalize(&rc, pStmt);

  /* Check if this database has the same set of SQL statements as the 
  ** current db. */
  if( bFailed==0 ){
    shellPreparePrintf(pState->db, &rc, &pStmt, 
        "SELECT 1 FROM _shared_schema_tmp.sqlite_master AS o "
        "WHERE sql IS NOT ("
        "  SELECT sql FROM main.sqlite_master "
        "    WHERE name IS o.name AND type IS o.type"
        ")"
    );
    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
      utf8_printf(pState->out, "%s is NOT compatible (SQL)\n", zDb);
      bFailed = 1;
    }
    shellFinalize(&rc, pStmt);
  }

  /* Check if this database has the same set of root pages as the current 
  ** db. */
  if( bFailed==0 ){
    shellPreparePrintf(pState->db, &rc, &pStmt, 
        "SELECT 1 FROM _shared_schema_tmp.sqlite_master AS o "
        "WHERE rootpage IS NOT ("
        "  SELECT rootpage FROM main.sqlite_master "
        "    WHERE name IS o.name AND type IS o.type"
        ")"
    );
    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
      if( peFix==0 ){
        utf8_printf(pState->out, "%s is NOT compatible (root pages)\n", zDb);
      }
      bFailed = 1;
      if( peFix ) *peFix = 1;
    }
    shellFinalize(&rc, pStmt);
  }

  if( bFailed==0 ){
    shellPreparePrintf(pState->db, &rc, &pStmt, 
        "SELECT 1 WHERE ("
        "  SELECT group_concat(rootpage || '.' || name || '.' || sql, '.') "
        "  FROM _shared_schema_tmp.sqlite_master"
        ") IS NOT ("
        "  SELECT group_concat(rootpage || '.' || name || '.' || sql, '.') "
        "  FROM main.sqlite_master"
        ")"
    );
    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
      if( peFix==0 ){
        utf8_printf(pState->out, 
            "%s is NOT compatible (order of sqlite_master rows)\n", zDb
        );
      }
      bFailed = 1;
      if( peFix ) *peFix = 2;
    }
    shellFinalize(&rc, pStmt);
  }

  if( bFailed==0 ){
    int iMain = -1;
    int iNew = +1;
    shellPreparePrintf(pState->db, &rc, &pStmt, 
        "PRAGMA main.schema_version"
    );
    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
      iMain = sqlite3_column_int(pStmt, 0);
    }
    shellFinalize(&rc, pStmt);
    shellPreparePrintf(pState->db, &rc, &pStmt, 
        "PRAGMA _shared_schema_tmp.schema_version"
    );
    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
      iNew = sqlite3_column_int(pStmt, 0);
    }
    shellFinalize(&rc, pStmt);
    if( rc==SQLITE_OK && iMain!=iNew ){
      if( peFix==0 ){
        utf8_printf(pState->out, 
            "%s is NOT compatible (schema cookie)\n", zDb
        );
      }
      bFailed = 1;
      if( peFix ) *peFix = 3;
    }
  }

  if( rc==SQLITE_OK && bFailed==0 ){
    utf8_printf(pState->out, "%s is compatible\n", zDb);
  }

  sqlite3_exec(pState->db, "DETACH _shared_schema_tmp", 0, 0, 0);
  return rc;
}

/*
** .shared-schema check|fix DB1 DB2...
*/
static int sharedSchemaDotCommand(
  ShellState *pState,             /* Current shell tool state */
  char **azArg,                   /* Array of arguments passed to dot command */
  int nArg                        /* Number of entries in azArg[] */
){
  int rc = SQLITE_OK;
  int bFix = 0;                   /* Fix databases if possible */
  int n1;
  int i;
  if( nArg<3 ){
    goto shared_schema_usage;
  }

  n1 = (int)strlen(azArg[1]);
  if( n1>0 && n1<=3 && memcmp("fix", azArg[1], n1)==0 ){
    bFix = 1;
  }else if( n1==0 || n1>5 || memcmp("check", azArg[1], n1) ){
    goto shared_schema_usage;
  }

  for(i=2; rc==SQLITE_OK && i<nArg; i++){
    int eFix = 0;
    rc = sharedSchemaCheck(pState, azArg[i], bFix ? &eFix : 0);
    if( rc==SQLITE_OK && bFix && eFix ){
      utf8_printf(pState->out, "Fixing %s... ", azArg[i]);
      fflush(pState->out);
      rc = sharedSchemaFix(pState, azArg[i], eFix);
      if( rc==SQLITE_OK ){
        rc = sharedSchemaCheck(pState, azArg[i], &eFix);
        if( rc==SQLITE_OK && eFix ){
          utf8_printf(pState->out, "VACUUMing main... ");
          fflush(pState->out);
          rc = sqlite3_exec(pState->db, "VACUUM main", 0, 0, 0);
          if( rc==SQLITE_OK ){
            rc = sharedSchemaCheck(pState, azArg[i], 0);
          }
        }
      }
    }
  }

  return rc;
 shared_schema_usage:
  raw_printf(stderr, "usage: .shared-schema check|fix DB1 DB2...\n");
  return SQLITE_ERROR;
}

/*
** When running the ".recover" command, each output table, and the special
** orphaned row table if it is required, is represented by an instance
** of the following struct.
*/
typedef struct RecoverTable RecoverTable;
................................................................................
      }else if( optionMatch(z, "zip") ){
        p->openMode = SHELL_OPEN_ZIPFILE;
#endif
      }else if( optionMatch(z, "append") ){
        p->openMode = SHELL_OPEN_APPENDVFS;
      }else if( optionMatch(z, "readonly") ){
        p->openMode = SHELL_OPEN_READONLY;
      }else if( optionMatch(z, "sharedschema") ){
        p->openMode = SHELL_OPEN_SHAREDSCHEMA;
      }else if( optionMatch(z, "nofollow") ){
        p->openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifdef SQLITE_ENABLE_DESERIALIZE
      }else if( optionMatch(z, "deserialize") ){
        p->openMode = SHELL_OPEN_DESERIALIZE;
      }else if( optionMatch(z, "hexdb") ){
        p->openMode = SHELL_OPEN_HEXDB;
................................................................................
    if( bDebug ){
      utf8_printf(p->out, "%s\n", zSql);
    }else{
      shell_exec(p, zSql, 0);
    }
    sqlite3_free(zSql);
  }else

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
  if( c=='s' && strncmp(azArg[0], "shared-schema", n)==0 ){
    open_db(p, 0);
    sharedSchemaDotCommand(p, azArg, nArg);
  }else
#endif

#ifndef SQLITE_NOHAVE_SYSTEM
  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
    int i, x;
................................................................................
    }else if( strcmp(z,"-deserialize")==0 ){
      data.openMode = SHELL_OPEN_DESERIALIZE;
    }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
      data.szMax = integerValue(argv[++i]);
#endif
    }else if( strcmp(z,"-readonly")==0 ){
      data.openMode = SHELL_OPEN_READONLY;
    }else if( strcmp(z,"-sharedschema")==0 ){
      data.openMode = SHELL_OPEN_SHAREDSCHEMA;
    }else if( strcmp(z,"-nofollow")==0 ){
      data.openFlags = SQLITE_OPEN_NOFOLLOW;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    }else if( strncmp(z, "-A",2)==0 ){
      /* All remaining command-line arguments are passed to the ".archive"
      ** command, so ignore them */
      break;
................................................................................
    }else if( strcmp(z,"-deserialize")==0 ){
      data.openMode = SHELL_OPEN_DESERIALIZE;
    }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
      data.szMax = integerValue(argv[++i]);
#endif
    }else if( strcmp(z,"-readonly")==0 ){
      data.openMode = SHELL_OPEN_READONLY;
    }else if( strcmp(z,"-sharedschema")==0 ){
      data.openMode = SHELL_OPEN_SHAREDSCHEMA;
    }else if( strcmp(z,"-nofollow")==0 ){
      data.openFlags |= SQLITE_OPEN_NOFOLLOW;
    }else if( strcmp(z,"-ascii")==0 ){
      data.mode = MODE_Ascii;
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
                       SEP_Unit);
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,

Changes to src/sqlite.h.in.

569
570
571
572
573
574
575


576
577
578
579
580
581
582
583
584
585
#define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */
#define SQLITE_OPEN_NOFOLLOW         0x01000000  /* Ok for sqlite3_open_v2() */

/* Reserved:                         0x00F00000 */


/* Legacy compatibility: */
#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */


/*
** CAPI3REF: Device Characteristics
**
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
** object returns an integer which is a vector of these
** bit values expressing I/O characteristics of the mass storage







>
>


<







569
570
571
572
573
574
575
576
577
578
579

580
581
582
583
584
585
586
#define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */
#define SQLITE_OPEN_NOFOLLOW         0x01000000  /* Ok for sqlite3_open_v2() */

/* Reserved:                         0x00F00000 */
#define SQLITE_OPEN_SHARED_SCHEMA    0x01000000  /* Ok for sqlite3_open_v2() */

/* Legacy compatibility: */
#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */


/*
** CAPI3REF: Device Characteristics
**
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
** object returns an integer which is a vector of these
** bit values expressing I/O characteristics of the mass storage

Changes to src/sqliteInt.h.

1109
1110
1111
1112
1113
1114
1115

1116
1117
1118
1119
1120
1121
1122
....
1242
1243
1244
1245
1246
1247
1248




1249
1250
1251
1252
1253
1254
1255
....
1273
1274
1275
1276
1277
1278
1279



1280
1281
1282
1283
1284
1285
1286
....
1588
1589
1590
1591
1592
1593
1594






1595
1596
1597
1598
1599
1600
1601
....
1668
1669
1670
1671
1672
1673
1674



1675
1676
1677
1678
1679
1680
1681
....
2108
2109
2110
2111
2112
2113
2114



2115
2116
2117
2118
2119
2120
2121
....
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
....
3523
3524
3525
3526
3527
3528
3529



3530
3531
3532
3533
3534
3535
3536
....
3635
3636
3637
3638
3639
3640
3641

3642
3643
3644
3645
3646
3647
3648
....
4644
4645
4646
4647
4648
4649
4650























4651
4652
4653
4654
4655
4656
4657
typedef struct AuthContext AuthContext;
typedef struct AutoincInfo AutoincInfo;
typedef struct Bitvec Bitvec;
typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Db Db;
typedef struct Schema Schema;

typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
typedef struct IdList IdList;
................................................................................
*/
struct Db {
  char *zDbSName;      /* Name of this database. (schema name, not filename) */
  Btree *pBt;          /* The B*Tree structure for this database file */
  u8 safety_level;     /* How aggressive at syncing data to disk */
  u8 bSyncSet;         /* True if "PRAGMA synchronous=N" has been run */
  Schema *pSchema;     /* Pointer to database schema (possibly shared) */




};

/*
** An instance of the following structure stores a database schema.
**
** Most Schema objects are associated with a Btree.  The exception is
** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
................................................................................
  Hash trigHash;       /* All triggers indexed by name */
  Hash fkeyHash;       /* All foreign keys by referenced table name */
  Table *pSeqTab;      /* The sqlite_sequence table used by AUTOINCREMENT */
  u8 file_format;      /* Schema format version for this file */
  u8 enc;              /* Text encoding used by this database */
  u16 schemaFlags;     /* Flags associated with this schema */
  int cache_size;      /* Number of pages to use in the cache */



};

/*
** These macros can be used to test, set, or clear bits in the
** Db.pSchema->flags field.
*/
#define DbHasProperty(D,I,P)     (((D)->aDb[I].pSchema->schemaFlags&(P))==(P))
................................................................................
  sqlite3 *pNextBlocked;        /* Next in list of all blocked connections */
#endif
#ifdef SQLITE_USER_AUTHENTICATION
  sqlite3_userauth auth;        /* User authentication information */
#endif
};







/*
** A macro to discover the encoding of a database.
*/
#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
#define ENC(db)        ((db)->enc)

/*
................................................................................
#define DBFLAG_PreferBuiltin  0x0002  /* Preference to built-in funcs */
#define DBFLAG_Vacuum         0x0004  /* Currently in a VACUUM */
#define DBFLAG_VacuumInto     0x0008  /* Currently running VACUUM INTO */
#define DBFLAG_SchemaKnownOk  0x0010  /* Schema is known to be valid */
#define DBFLAG_InternalFunc   0x0020  /* Allow use of internal functions */
#define DBFLAG_EncodingFixed  0x0040  /* No longer possible to change enc. */




/*
** Bits of the sqlite3.dbOptFlags field that are used by the
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
** selectively disable various optimizations.
*/
#define SQLITE_QueryFlattener 0x0001   /* Query flattening */
#define SQLITE_WindowFunc     0x0002   /* Use xInverse for window functions */
................................................................................
  Module *pMod;             /* Pointer to module implementation */
  sqlite3_vtab *pVtab;      /* Pointer to vtab instance */
  int nRef;                 /* Number of pointers to this structure */
  u8 bConstraint;           /* True if constraints are supported */
  u8 eVtabRisk;             /* Riskiness of allowing hacker access */
  int iSavepoint;           /* Depth of the SAVEPOINT stack */
  VTable *pNext;            /* Next in linked list (see above) */



};

/* Allowed values for VTable.eVtabRisk
*/
#define SQLITE_VTABRISK_Low          0
#define SQLITE_VTABRISK_Normal       1
#define SQLITE_VTABRISK_High         2
................................................................................
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nTableLock;        /* Number of locks in aTableLock */
  TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
  AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
  Parse *pToplevel;    /* Parse structure for main program (or NULL) */
  Table *pTriggerTab;  /* Table triggers are being coded for */
  Parse *pParentParse; /* Parent parser if this parser is nested */
  AggInfo *pAggList;   /* List of all AggInfo objects */
  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
  u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
  u32 oldmask;         /* Mask of old.* columns referenced */
  u32 newmask;         /* Mask of new.* columns referenced */
  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
................................................................................
  Expr *pWhen;            /* The WHEN clause of the expression (may be NULL) */
  IdList *pColumns;       /* If this is an UPDATE OF <column-list> trigger,
                             the <column-list> is stored here */
  Schema *pSchema;        /* Schema containing the trigger */
  Schema *pTabSchema;     /* Schema containing the table */
  TriggerStep *step_list; /* Link list of trigger program steps             */
  Trigger *pNext;         /* Next trigger associated with the table */



};

/*
** A trigger is either a BEFORE or an AFTER trigger.  The following constants
** determine which.
**
** If there are multiple triggers, you might of some BEFORE and some AFTER.
................................................................................
typedef struct {
  sqlite3 *db;        /* The database being initialized */
  char **pzErrMsg;    /* Error message stored here */
  int iDb;            /* 0 for main database.  1 for TEMP, 2.. for ATTACHed */
  int rc;             /* Result code stored here */
  u32 mInitFlags;     /* Flags controlling error messages */
  u32 nInitRow;       /* Number of rows processed */

  Pgno mxPage;        /* Maximum page number.  0 for no limit. */
} InitData;

/*
** Allowed values for mInitFlags
*/
#define INITFLAG_AlterTable   0x0001  /* This is a reparse after ALTER TABLE */
................................................................................
int sqlite3FindDbName(sqlite3 *, const char *);
int sqlite3AnalysisLoad(sqlite3*,int iDB);
void sqlite3DeleteIndexSamples(sqlite3*,Index*);
void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
void sqlite3SchemaClear(void *);























Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int);
void sqlite3KeyInfoUnref(KeyInfo*);
KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);







>







 







>
>
>
>







 







>
>
>







 







>
>
>
>
>
>







 







>
>
>







 







>
>
>







 







<







 







>
>
>







 







>







 







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







1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
....
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
....
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
....
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
....
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
....
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
....
3380
3381
3382
3383
3384
3385
3386

3387
3388
3389
3390
3391
3392
3393
....
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
....
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
....
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
typedef struct AuthContext AuthContext;
typedef struct AutoincInfo AutoincInfo;
typedef struct Bitvec Bitvec;
typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Db Db;
typedef struct Schema Schema;
typedef struct SchemaPool SchemaPool;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
typedef struct IdList IdList;
................................................................................
*/
struct Db {
  char *zDbSName;      /* Name of this database. (schema name, not filename) */
  Btree *pBt;          /* The B*Tree structure for this database file */
  u8 safety_level;     /* How aggressive at syncing data to disk */
  u8 bSyncSet;         /* True if "PRAGMA synchronous=N" has been run */
  Schema *pSchema;     /* Pointer to database schema (possibly shared) */
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  SchemaPool *pSPool;  /* For REUSE_SCHEMA mode */
  VTable *pVTable;     /* List of all VTable objects (REUSE_SCHEMA mode only) */
#endif
};

/*
** An instance of the following structure stores a database schema.
**
** Most Schema objects are associated with a Btree.  The exception is
** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
................................................................................
  Hash trigHash;       /* All triggers indexed by name */
  Hash fkeyHash;       /* All foreign keys by referenced table name */
  Table *pSeqTab;      /* The sqlite_sequence table used by AUTOINCREMENT */
  u8 file_format;      /* Schema format version for this file */
  u8 enc;              /* Text encoding used by this database */
  u16 schemaFlags;     /* Flags associated with this schema */
  int cache_size;      /* Number of pages to use in the cache */
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  Schema *pNext;       /* Next Schema object SchemaPool (REUSE_SCHEMA) */
#endif
};

/*
** These macros can be used to test, set, or clear bits in the
** Db.pSchema->flags field.
*/
#define DbHasProperty(D,I,P)     (((D)->aDb[I].pSchema->schemaFlags&(P))==(P))
................................................................................
  sqlite3 *pNextBlocked;        /* Next in list of all blocked connections */
#endif
#ifdef SQLITE_USER_AUTHENTICATION
  sqlite3_userauth auth;        /* User authentication information */
#endif
};

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
# define IsSharedSchema(db) (((db)->openFlags & SQLITE_OPEN_SHARED_SCHEMA)!=0)
#else
# define IsSharedSchema(db) 0
#endif

/*
** A macro to discover the encoding of a database.
*/
#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
#define ENC(db)        ((db)->enc)

/*
................................................................................
#define DBFLAG_PreferBuiltin  0x0002  /* Preference to built-in funcs */
#define DBFLAG_Vacuum         0x0004  /* Currently in a VACUUM */
#define DBFLAG_VacuumInto     0x0008  /* Currently running VACUUM INTO */
#define DBFLAG_SchemaKnownOk  0x0010  /* Schema is known to be valid */
#define DBFLAG_InternalFunc   0x0020  /* Allow use of internal functions */
#define DBFLAG_EncodingFixed  0x0040  /* No longer possible to change enc. */

#define DBFLAG_SchemaInuse    0x0080  /* Do not release sharable schemas */
#define DBFLAG_FreeSchema     0x0100  /* Free extra shared schemas on release */

/*
** Bits of the sqlite3.dbOptFlags field that are used by the
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
** selectively disable various optimizations.
*/
#define SQLITE_QueryFlattener 0x0001   /* Query flattening */
#define SQLITE_WindowFunc     0x0002   /* Use xInverse for window functions */
................................................................................
  Module *pMod;             /* Pointer to module implementation */
  sqlite3_vtab *pVtab;      /* Pointer to vtab instance */
  int nRef;                 /* Number of pointers to this structure */
  u8 bConstraint;           /* True if constraints are supported */
  u8 eVtabRisk;             /* Riskiness of allowing hacker access */
  int iSavepoint;           /* Depth of the SAVEPOINT stack */
  VTable *pNext;            /* Next in linked list (see above) */
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  char *zName;              /* Table name (REUSE_SCHEMA mode) */
#endif
};

/* Allowed values for VTable.eVtabRisk
*/
#define SQLITE_VTABRISK_Low          0
#define SQLITE_VTABRISK_Normal       1
#define SQLITE_VTABRISK_High         2
................................................................................
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nTableLock;        /* Number of locks in aTableLock */
  TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
  AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
  Parse *pToplevel;    /* Parse structure for main program (or NULL) */
  Table *pTriggerTab;  /* Table triggers are being coded for */

  AggInfo *pAggList;   /* List of all AggInfo objects */
  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
  u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
  u32 oldmask;         /* Mask of old.* columns referenced */
  u32 newmask;         /* Mask of new.* columns referenced */
  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
................................................................................
  Expr *pWhen;            /* The WHEN clause of the expression (may be NULL) */
  IdList *pColumns;       /* If this is an UPDATE OF <column-list> trigger,
                             the <column-list> is stored here */
  Schema *pSchema;        /* Schema containing the trigger */
  Schema *pTabSchema;     /* Schema containing the table */
  TriggerStep *step_list; /* Link list of trigger program steps             */
  Trigger *pNext;         /* Next trigger associated with the table */
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  char *zTabSchema;       /* Temp triggers in IsSharedSchema() dbs only */
#endif
};

/*
** A trigger is either a BEFORE or an AFTER trigger.  The following constants
** determine which.
**
** If there are multiple triggers, you might of some BEFORE and some AFTER.
................................................................................
typedef struct {
  sqlite3 *db;        /* The database being initialized */
  char **pzErrMsg;    /* Error message stored here */
  int iDb;            /* 0 for main database.  1 for TEMP, 2.. for ATTACHed */
  int rc;             /* Result code stored here */
  u32 mInitFlags;     /* Flags controlling error messages */
  u32 nInitRow;       /* Number of rows processed */
  u64 cksum;          /* Schema checksum for REUSE_SCHEMA mode */
  Pgno mxPage;        /* Maximum page number.  0 for no limit. */
} InitData;

/*
** Allowed values for mInitFlags
*/
#define INITFLAG_AlterTable   0x0001  /* This is a reparse after ALTER TABLE */
................................................................................
int sqlite3FindDbName(sqlite3 *, const char *);
int sqlite3AnalysisLoad(sqlite3*,int iDB);
void sqlite3DeleteIndexSamples(sqlite3*,Index*);
void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
void sqlite3SchemaClear(void *);
void sqlite3SchemaClearOrDisconnect(sqlite3*, int);

#ifdef SQLITE_ENABLE_SHARED_SCHEMA 
int sqlite3SchemaConnect(sqlite3*, int, u64);
int sqlite3SchemaDisconnect(sqlite3 *, int, int);
Schema *sqlite3SchemaExtract(SchemaPool*);
int sqlite3SchemaLoad(sqlite3*, int, int*, char**);
void sqlite3SchemaReleaseAll(sqlite3*);
void sqlite3SchemaRelease(sqlite3*, int);
void sqlite3SchemaAdjustUsed(sqlite3*, int, int, int*);
void sqlite3SchemaWritable(Parse*, int);
void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease);
int sqlite3LockReusableSchema(sqlite3 *db);
#else
# define sqlite3SchemaWritable(x,y)
# define sqlite3UnlockReusableSchema(x,y)
# define sqlite3LockReusableSchema(x) 0
# define sqlite3SchemaDisconnect(x,y,z) SQLITE_OK
# define sqlite3SchemaLoad(w,x,y,z) SQLITE_OK
# define sqlite3SchemaRelease(y,z)
# define sqlite3SchemaConnect(x,y,z) SQLITE_OK
#endif

Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int);
void sqlite3KeyInfoUnref(KeyInfo*);
KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);

Changes to src/status.c.

284
285
286
287
288
289
290

291
292

293
294











295
296
297
298
299
300
301
302
...
310
311
312
313
314
315
316




317



318
319
320
321
322
323
324
    ** *pCurrent gets an accurate estimate of the amount of memory used
    ** to store the schema for all databases (main, temp, and any ATTACHed
    ** databases.  *pHighwater is set to zero.
    */
    case SQLITE_DBSTATUS_SCHEMA_USED: {
      int i;                      /* Used to iterate through schemas */
      int nByte = 0;              /* Used to accumulate return value */


      sqlite3BtreeEnterAll(db);

      db->pnBytesFreed = &nByte;
      for(i=0; i<db->nDb; i++){











        Schema *pSchema = db->aDb[i].pSchema;
        if( ALWAYS(pSchema!=0) ){
          HashElem *p;

          nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
              pSchema->tblHash.count 
            + pSchema->trigHash.count
            + pSchema->idxHash.count
................................................................................
          for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
            sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
          }
          for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
            sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
          }
        }




      }



      db->pnBytesFreed = 0;
      sqlite3BtreeLeaveAll(db);

      *pHighwater = 0;
      *pCurrent = nByte;
      break;
    }







>


>


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







 







>
>
>
>
|
>
>
>







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
...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
    ** *pCurrent gets an accurate estimate of the amount of memory used
    ** to store the schema for all databases (main, temp, and any ATTACHed
    ** databases.  *pHighwater is set to zero.
    */
    case SQLITE_DBSTATUS_SCHEMA_USED: {
      int i;                      /* Used to iterate through schemas */
      int nByte = 0;              /* Used to accumulate return value */
      int bReleaseSchema;

      sqlite3BtreeEnterAll(db);
      bReleaseSchema = sqlite3LockReusableSchema(db);
      db->pnBytesFreed = &nByte;
      for(i=0; i<db->nDb; i++){
        Schema *pSchema;
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
        int bUnload = 0;
        int nUsed = nByte;
        if( db->aDb[i].pSPool ){
          char *zDummy = 0;
          rc = sqlite3SchemaLoad(db, i, &bUnload, &zDummy);
          sqlite3_free(zDummy);
          if( rc ) break;
        }
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
        pSchema = db->aDb[i].pSchema;
        if( ALWAYS(pSchema!=0) ){
          HashElem *p;

          nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
              pSchema->tblHash.count 
            + pSchema->trigHash.count
            + pSchema->idxHash.count
................................................................................
          for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
            sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
          }
          for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
            sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
          }
        }
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
        if( db->aDb[i].pSPool ){
          if( bUnload ) sqlite3SchemaRelease(db, i);
          sqlite3SchemaAdjustUsed(db, i, nUsed, &nByte);
        }
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
      }
      sqlite3UnlockReusableSchema(db, bReleaseSchema);
      db->pnBytesFreed = 0;
      sqlite3BtreeLeaveAll(db);

      *pHighwater = 0;
      *pCurrent = nByte;
      break;
    }

Changes to src/tclsqlite.c.

3662
3663
3664
3665
3666
3667
3668



3669
3670
3671
3672
3673
3674
3675
....
3793
3794
3795
3796
3797
3798
3799










3800
3801
3802
3803
3804
3805
3806
  Tcl_Interp *interp,
  Tcl_Obj *const*objv
){
  Tcl_WrongNumArgs(interp, 1, objv,
    "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
    " ?-nofollow BOOLEAN?"
    " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"



  );
  return TCL_ERROR;
}

/*
**   sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
**                           ?-create BOOLEAN? ?-nomutex BOOLEAN?
................................................................................
      int b;
      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
      if( b ){
        flags |= SQLITE_OPEN_URI;
      }else{
        flags &= ~SQLITE_OPEN_URI;
      }










    }else if( strcmp(zArg, "-translatefilename")==0 ){
      if( Tcl_GetBooleanFromObj(interp, objv[i], &bTranslateFileName) ){
        return TCL_ERROR;
      }
    }else{
      Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
      return TCL_ERROR;







>
>
>







 







>
>
>
>
>
>
>
>
>
>







3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
....
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
  Tcl_Interp *interp,
  Tcl_Obj *const*objv
){
  Tcl_WrongNumArgs(interp, 1, objv,
    "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
    " ?-nofollow BOOLEAN?"
    " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    " ?-shared-schema BOOLEAN?"
#endif
  );
  return TCL_ERROR;
}

/*
**   sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
**                           ?-create BOOLEAN? ?-nomutex BOOLEAN?
................................................................................
      int b;
      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
      if( b ){
        flags |= SQLITE_OPEN_URI;
      }else{
        flags &= ~SQLITE_OPEN_URI;
      }
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    }else if( strcmp(zArg, "-shared-schema")==0 ){
      int b;
      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
      if( b ){
        flags |= SQLITE_OPEN_SHARED_SCHEMA;
      }else{
        flags &= ~SQLITE_OPEN_SHARED_SCHEMA;
      }
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
    }else if( strcmp(zArg, "-translatefilename")==0 ){
      if( Tcl_GetBooleanFromObj(interp, objv[i], &bTranslateFileName) ){
        return TCL_ERROR;
      }
    }else{
      Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
      return TCL_ERROR;

Changes to src/test_config.c.

759
760
761
762
763
764
765






766
767
768
769
770
771
772
#endif

#ifdef SQLITE_OMIT_WINDOWFUNC
  Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "0", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "1", TCL_GLOBAL_ONLY);
#endif







#define LINKVAR(x) { \
    static const int cv_ ## x = SQLITE_ ## x; \
    Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \
                TCL_LINK_INT | TCL_LINK_READ_ONLY); }

  LINKVAR( MAX_LENGTH );







>
>
>
>
>
>







759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
#endif

#ifdef SQLITE_OMIT_WINDOWFUNC
  Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "0", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "1", TCL_GLOBAL_ONLY);
#endif

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  Tcl_SetVar2(interp, "sqlite_options", "sharedschema", "1", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "sharedschema", "0", TCL_GLOBAL_ONLY);
#endif

#define LINKVAR(x) { \
    static const int cv_ ## x = SQLITE_ ## x; \
    Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \
                TCL_LINK_INT | TCL_LINK_READ_ONLY); }

  LINKVAR( MAX_LENGTH );

Added src/test_schemapool.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
/*
** 2006 June 10
**
** 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.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/

/*
** None of this works unless we have virtual tables.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST)

#include <tcl.h>

#ifdef SQLITE_ENABLE_SHARED_SCHEMA

#include "sqliteInt.h"

/* The code in this file defines a sqlite3 virtual-table module with
** the following schema.
*/
#define SCHEMAPOOL_SCHEMA \
"CREATE TABLE x("         \
"  cksum   INTEGER, "     \
"  nref    INTEGER, "     \
"  nschema INTEGER, "     \
"  ndelete INTEGER  "     \
")"

#define SCHEMAPOOL_NFIELD 4

typedef struct schemapool_vtab schemapool_vtab;
typedef struct schemapool_cursor schemapool_cursor;

/* A schema table object */
struct schemapool_vtab {
  sqlite3_vtab base;
};

/* A schema table cursor object */
struct schemapool_cursor {
  sqlite3_vtab_cursor base;
  sqlite3_int64 *aData;
  int iRow;
  int nRow;
};

/*
** Table destructor for the schema module.
*/
static int schemaPoolDestroy(sqlite3_vtab *pVtab){
  sqlite3_free(pVtab);
  return 0;
}

/*
** Table constructor for the schema module.
*/
static int schemaPoolCreate(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  int rc = SQLITE_NOMEM;
  schemapool_vtab *pVtab = sqlite3_malloc(sizeof(schemapool_vtab));
  if( pVtab ){
    memset(pVtab, 0, sizeof(schemapool_vtab));
    rc = sqlite3_declare_vtab(db, SCHEMAPOOL_SCHEMA);
    if( rc!=SQLITE_OK ){
      sqlite3_free(pVtab);
      pVtab = 0;
    }
  }
  *ppVtab = (sqlite3_vtab *)pVtab;
  return rc;
}

/*
** Open a new cursor on the schema table.
*/
static int schemaPoolOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  int rc = SQLITE_NOMEM;
  schemapool_cursor *pCur;
  pCur = sqlite3_malloc(sizeof(schemapool_cursor));
  if( pCur ){
    memset(pCur, 0, sizeof(schemapool_cursor));
    *ppCursor = (sqlite3_vtab_cursor*)pCur;
    rc = SQLITE_OK;
  }
  return rc;
}

/*
** Close a schema table cursor.
*/
static int schemaPoolClose(sqlite3_vtab_cursor *cur){
  schemapool_cursor *pCur = (schemapool_cursor*)cur;
  sqlite3_free(pCur->aData);
  sqlite3_free(pCur);
  return SQLITE_OK;
}

/*
** Retrieve a column of data.
*/
static int schemaPoolColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  schemapool_cursor *pCur = (schemapool_cursor*)cur;
  assert( i==0 || i==1 || i==2 || i==3 );
  sqlite3_result_int64(ctx, pCur->aData[pCur->iRow*SCHEMAPOOL_NFIELD + i]);
  return SQLITE_OK;
}

/*
** Retrieve the current rowid.
*/
static int schemaPoolRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  schemapool_cursor *pCur = (schemapool_cursor*)cur;
  *pRowid = pCur->iRow + 1;
  return SQLITE_OK;
}

static int schemaPoolEof(sqlite3_vtab_cursor *cur){
  schemapool_cursor *pCur = (schemapool_cursor*)cur;
  return pCur->iRow>=pCur->nRow;
}

/*
** Advance the cursor to the next row.
*/
static int schemaPoolNext(sqlite3_vtab_cursor *cur){
  schemapool_cursor *pCur = (schemapool_cursor*)cur;
  pCur->iRow++;
  return SQLITE_OK;
}

struct SchemaPool {
  int nRef;                       /* Number of pointers to this object */
  int nDelete;                    /* Schema objects deleted by ReleaseAll() */
  u64 cksum;                      /* Checksum for this Schema contents */
  Schema *pSchema;                /* Linked list of Schema objects */
  Schema sSchema;                 /* The single dummy schema object */
  SchemaPool *pNext;              /* Next element in schemaPoolList */
};
extern SchemaPool *sqlite3SchemaPoolList(void);

/*
** Reset a schemaPool table cursor.
*/
static int schemaPoolFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  SchemaPool *pSPool;
  schemapool_cursor *pCur = (schemapool_cursor*)pVtabCursor;

  sqlite3_free(pCur->aData);
  pCur->aData = 0;
  pCur->nRow = 0;
  pCur->iRow = 0;

  for(pSPool = sqlite3SchemaPoolList(); pSPool; pSPool=pSPool->pNext){
    pCur->nRow++;
  }

  if( pCur->nRow ){
    int iRow = 0;
    int nByte = SCHEMAPOOL_NFIELD * pCur->nRow * sizeof(i64);
    pCur->aData = (i64*)sqlite3_malloc(nByte);
    if( pCur->aData==0 ) return SQLITE_NOMEM;
    for(pSPool = sqlite3SchemaPoolList(); pSPool; pSPool=pSPool->pNext){
      Schema *p;
      i64 nSchema = 0;
      for(p=pSPool->pSchema; p; p=p->pNext){
        nSchema++;
      }
      pCur->aData[0 + iRow*SCHEMAPOOL_NFIELD] = pSPool->cksum;
      pCur->aData[1 + iRow*SCHEMAPOOL_NFIELD] = (i64)pSPool->nRef;
      pCur->aData[2 + iRow*SCHEMAPOOL_NFIELD] = nSchema;
      pCur->aData[3 + iRow*SCHEMAPOOL_NFIELD] = (i64)pSPool->nDelete;
      iRow++;
    }
  }

  return SQLITE_OK;
}

/*
** Analyse the WHERE condition.
*/
static int schemaPoolBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  return SQLITE_OK;
}

/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/
static sqlite3_module schemaPoolModule = {
  0,                           /* iVersion */
  schemaPoolCreate,
  schemaPoolCreate,
  schemaPoolBestIndex,
  schemaPoolDestroy,
  schemaPoolDestroy,
  schemaPoolOpen,              /* xOpen - open a cursor */
  schemaPoolClose,             /* xClose - close a cursor */
  schemaPoolFilter,            /* xFilter - configure scan constraints */
  schemaPoolNext,              /* xNext - advance a cursor */
  schemaPoolEof,               /* xEof */
  schemaPoolColumn,            /* xColumn - read data */
  schemaPoolRowid,             /* xRowid - read data */
  0,                           /* xUpdate */
  0,                           /* xBegin */
  0,                           /* xSync */
  0,                           /* xCommit */
  0,                           /* xRollback */
  0,                           /* xFindMethod */
  0,                           /* xRename */
};

/*
** Decode a pointer to an sqlite3 object.
*/
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);

/*
** Register the schema virtual table module.
*/
static int SQLITE_TCLAPI register_schemapool_module(
  ClientData clientData, /* Not used */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3_create_module(db, "schemapool", &schemaPoolModule, 0);
#endif
  return TCL_OK;
}

#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST) */

/*
** Register commands with the TCL interpreter.
*/
int Sqlitetestschemapool_Init(Tcl_Interp *interp){
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
     void *clientData;
  } aObjCmd[] = {
     { "register_schemapool_module", register_schemapool_module, 0 },
  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
  }
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
  return TCL_OK;
}

Changes to src/test_tclsh.c.

73
74
75
76
77
78
79

80
81
82
83
84
85
86
...
143
144
145
146
147
148
149

150
151
152
153
154
155
156
  extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
  extern int Sqlitetest_func_Init(Tcl_Interp*);
  extern int Sqlitetest_hexio_Init(Tcl_Interp*);
  extern int Sqlitetest_init_Init(Tcl_Interp*);
  extern int Sqlitetest_malloc_Init(Tcl_Interp*);
  extern int Sqlitetest_mutex_Init(Tcl_Interp*);
  extern int Sqlitetestschema_Init(Tcl_Interp*);

  extern int Sqlitetestsse_Init(Tcl_Interp*);
  extern int Sqlitetesttclvar_Init(Tcl_Interp*);
  extern int Sqlitetestfs_Init(Tcl_Interp*);
  extern int SqlitetestThread_Init(Tcl_Interp*);
  extern int SqlitetestOnefile_Init();
  extern int SqlitetestOsinst_Init(Tcl_Interp*);
  extern int Sqlitetestbackup_Init(Tcl_Interp*);
................................................................................
  Sqlitetest_demovfs_Init(interp);
  Sqlitetest_func_Init(interp);
  Sqlitetest_hexio_Init(interp);
  Sqlitetest_init_Init(interp);
  Sqlitetest_malloc_Init(interp);
  Sqlitetest_mutex_Init(interp);
  Sqlitetestschema_Init(interp);

  Sqlitetesttclvar_Init(interp);
  Sqlitetestfs_Init(interp);
  SqlitetestThread_Init(interp);
  SqlitetestOnefile_Init();
  SqlitetestOsinst_Init(interp);
  Sqlitetestbackup_Init(interp);
  Sqlitetestintarray_Init(interp);







>







 







>







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
  extern int Sqlitetest_func_Init(Tcl_Interp*);
  extern int Sqlitetest_hexio_Init(Tcl_Interp*);
  extern int Sqlitetest_init_Init(Tcl_Interp*);
  extern int Sqlitetest_malloc_Init(Tcl_Interp*);
  extern int Sqlitetest_mutex_Init(Tcl_Interp*);
  extern int Sqlitetestschema_Init(Tcl_Interp*);
  extern int Sqlitetestschemapool_Init(Tcl_Interp*);
  extern int Sqlitetestsse_Init(Tcl_Interp*);
  extern int Sqlitetesttclvar_Init(Tcl_Interp*);
  extern int Sqlitetestfs_Init(Tcl_Interp*);
  extern int SqlitetestThread_Init(Tcl_Interp*);
  extern int SqlitetestOnefile_Init();
  extern int SqlitetestOsinst_Init(Tcl_Interp*);
  extern int Sqlitetestbackup_Init(Tcl_Interp*);
................................................................................
  Sqlitetest_demovfs_Init(interp);
  Sqlitetest_func_Init(interp);
  Sqlitetest_hexio_Init(interp);
  Sqlitetest_init_Init(interp);
  Sqlitetest_malloc_Init(interp);
  Sqlitetest_mutex_Init(interp);
  Sqlitetestschema_Init(interp);
  Sqlitetestschemapool_Init(interp);
  Sqlitetesttclvar_Init(interp);
  Sqlitetestfs_Init(interp);
  SqlitetestThread_Init(interp);
  SqlitetestOnefile_Init();
  SqlitetestOsinst_Init(interp);
  Sqlitetestbackup_Init(interp);
  Sqlitetestintarray_Init(interp);

Changes to src/tokenize.c.

558
559
560
561
562
563
564

565
566
567
568
569
570
571
...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
  int nErr = 0;                   /* Number of errors encountered */
  void *pEngine;                  /* The LEMON-generated LALR(1) parser */
  int n = 0;                      /* Length of the next token token */
  int tokenType;                  /* type of the next token */
  int lastTokenParsed = -1;       /* type of the previous token */
  sqlite3 *db = pParse->db;       /* The database connection */
  int mxSqlLen;                   /* Max length of an SQL string */

#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
#endif
  VVA_ONLY( u8 startedWithOom = db->mallocFailed );

  assert( zSql!=0 );
  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
................................................................................
    return SQLITE_NOMEM_BKPT;
  }
#endif
  assert( pParse->pNewTable==0 );
  assert( pParse->pNewTrigger==0 );
  assert( pParse->nVar==0 );
  assert( pParse->pVList==0 );
  pParse->pParentParse = db->pParse;
  db->pParse = pParse;
  while( 1 ){
    n = sqlite3GetToken((u8*)zSql, &tokenType);
    mxSqlLen -= n;
    if( mxSqlLen<0 ){
      pParse->rc = SQLITE_TOOBIG;
      break;
................................................................................
    sqlite3DbFreeNN(db, p);
  }
  while( pParse->pZombieTab ){
    Table *p = pParse->pZombieTab;
    pParse->pZombieTab = p->pNextZombie;
    sqlite3DeleteTable(db, p);
  }
  db->pParse = pParse->pParentParse;
  pParse->pParentParse = 0;
  assert( nErr==0 || pParse->rc!=SQLITE_OK );
  return nErr;
}


#ifdef SQLITE_ENABLE_NORMALIZE
/*







>







 







<







 







|
<







558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
...
594
595
596
597
598
599
600

601
602
603
604
605
606
607
...
720
721
722
723
724
725
726
727

728
729
730
731
732
733
734
  int nErr = 0;                   /* Number of errors encountered */
  void *pEngine;                  /* The LEMON-generated LALR(1) parser */
  int n = 0;                      /* Length of the next token token */
  int tokenType;                  /* type of the next token */
  int lastTokenParsed = -1;       /* type of the previous token */
  sqlite3 *db = pParse->db;       /* The database connection */
  int mxSqlLen;                   /* Max length of an SQL string */
  Parse *pParentParse = db->pParse;
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
#endif
  VVA_ONLY( u8 startedWithOom = db->mallocFailed );

  assert( zSql!=0 );
  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
................................................................................
    return SQLITE_NOMEM_BKPT;
  }
#endif
  assert( pParse->pNewTable==0 );
  assert( pParse->pNewTrigger==0 );
  assert( pParse->nVar==0 );
  assert( pParse->pVList==0 );

  db->pParse = pParse;
  while( 1 ){
    n = sqlite3GetToken((u8*)zSql, &tokenType);
    mxSqlLen -= n;
    if( mxSqlLen<0 ){
      pParse->rc = SQLITE_TOOBIG;
      break;
................................................................................
    sqlite3DbFreeNN(db, p);
  }
  while( pParse->pZombieTab ){
    Table *p = pParse->pZombieTab;
    pParse->pZombieTab = p->pNextZombie;
    sqlite3DeleteTable(db, p);
  }
  db->pParse = pParentParse;

  assert( nErr==0 || pParse->rc!=SQLITE_OK );
  return nErr;
}


#ifdef SQLITE_ENABLE_NORMALIZE
/*

Changes to src/trigger.c.

52
53
54
55
56
57
58

59






60
61
62





63


64
65

66
67

68
69
70
71
72
73
74
...
245
246
247
248
249
250
251






252
253
254
255
256
257
258
...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
552
553
554
555
556
557
558



559
560
561
562
563
564
565
...
623
624
625
626
627
628
629

630
631
632
633
634
635
636
  Trigger *pList = 0;                  /* List of triggers to return */

  if( pParse->disableTriggers ){
    return 0;
  }

  if( pTmpSchema!=pTab->pSchema ){

    HashElem *p;






    assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) );
    for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
      Trigger *pTrig = (Trigger *)sqliteHashData(p);





      if( pTrig->pTabSchema==pTab->pSchema


       && 0==sqlite3StrICmp(pTrig->table, pTab->zName) 
      ){

        pTrig->pNext = (pList ? pList : pTab->pTrigger);
        pList = pTrig;

      }
    }
  }

  return (pList ? pList : pTab->pTrigger);
}

................................................................................

  /* Build the Trigger object */
  pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger));
  if( pTrigger==0 ) goto trigger_cleanup;
  pTrigger->zName = zName;
  zName = 0;
  pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName);






  pTrigger->pSchema = db->aDb[iDb].pSchema;
  pTrigger->pTabSchema = pTab->pSchema;
  pTrigger->op = (u8)op;
  pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
  if( IN_RENAME_OBJECT ){
    sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName);
    pTrigger->pWhen = pWhen;
................................................................................
    sqlite3NestedParse(pParse,
       "INSERT INTO %Q." DFLT_SCHEMA_TABLE
       " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
       db->aDb[iDb].zDbSName, zName,
       pTrig->table, z);
    sqlite3DbFree(db, z);
    sqlite3ChangeCookie(pParse, iDb);
    sqlite3VdbeAddParseSchemaOp(v, iDb,
        sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
  }

  if( db->init.busy ){
    Trigger *pLink = pTrig;
    Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
................................................................................
** Recursively delete a Trigger structure
*/
void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
  if( pTrigger==0 ) return;
  sqlite3DeleteTriggerStep(db, pTrigger->step_list);
  sqlite3DbFree(db, pTrigger->zName);
  sqlite3DbFree(db, pTrigger->table);



  sqlite3ExprDelete(db, pTrigger->pWhen);
  sqlite3IdListDelete(db, pTrigger->pColumns);
  sqlite3DbFree(db, pTrigger);
}

/*
** This function is called to drop a trigger from the database schema. 
................................................................................
  Table   *pTable;
  Vdbe *v;
  sqlite3 *db = pParse->db;
  int iDb;

  iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
  assert( iDb>=0 && iDb<db->nDb );

  pTable = tableOfTrigger(pTrigger);
  assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
  if( pTable ){
    int code = SQLITE_DROP_TRIGGER;
    const char *zDb = db->aDb[iDb].zDbSName;
    const char *zTab = SCHEMA_TABLE(iDb);







>

>
>
>
>
>
>
|


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







 







>
>
>
>
>
>







 







|







 







>
>
>







 







>







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
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
...
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
  Trigger *pList = 0;                  /* List of triggers to return */

  if( pParse->disableTriggers ){
    return 0;
  }

  if( pTmpSchema!=pTab->pSchema ){
    sqlite3 *db = pParse->db;
    HashElem *p;
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
    char *zSchema = 0;
    if( IsSharedSchema(db) ){
      zSchema = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
    }
#endif
    assert( sqlite3SchemaMutexHeld(db, 0, pTmpSchema) );
    for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
      Trigger *pTrig = (Trigger *)sqliteHashData(p);

#ifdef SQLITE_ENABLE_SHARED_SCHEMA
      if( (zSchema==0 && pTrig->pTabSchema==pTab->pSchema)
       || (zSchema!=0 && 0==sqlite3StrICmp(pTrig->zTabSchema, zSchema)) )
#else 
      if( pTrig->pTabSchema==pTab->pSchema )
#endif
      {
        if( 0==sqlite3StrICmp(pTrig->table, pTab->zName) ){

          pTrig->pTabSchema = pTab->pSchema;
          pTrig->pNext = (pList ? pList : pTab->pTrigger);
          pList = pTrig;
        }
      }
    }
  }

  return (pList ? pList : pTab->pTrigger);
}

................................................................................

  /* Build the Trigger object */
  pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger));
  if( pTrigger==0 ) goto trigger_cleanup;
  pTrigger->zName = zName;
  zName = 0;
  pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName);
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  if( IsSharedSchema(db) && iDb==1 ){
    int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    pTrigger->zTabSchema = sqlite3DbStrDup(db, db->aDb[iTabDb].zDbSName);
  }
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
  pTrigger->pSchema = db->aDb[iDb].pSchema;
  pTrigger->pTabSchema = pTab->pSchema;
  pTrigger->op = (u8)op;
  pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
  if( IN_RENAME_OBJECT ){
    sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName);
    pTrigger->pWhen = pWhen;
................................................................................
    sqlite3NestedParse(pParse,
       "INSERT INTO %Q." DFLT_SCHEMA_TABLE
       " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
       db->aDb[iDb].zDbSName, zName,
       pTrig->table, z);
    sqlite3DbFree(db, z);
    sqlite3ChangeCookie(pParse, iDb);
    sqlite3VdbeAddParseSchemaOp(pParse, iDb,
        sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
  }

  if( db->init.busy ){
    Trigger *pLink = pTrig;
    Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
................................................................................
** Recursively delete a Trigger structure
*/
void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
  if( pTrigger==0 ) return;
  sqlite3DeleteTriggerStep(db, pTrigger->step_list);
  sqlite3DbFree(db, pTrigger->zName);
  sqlite3DbFree(db, pTrigger->table);
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  sqlite3DbFree(db, pTrigger->zTabSchema);
#endif
  sqlite3ExprDelete(db, pTrigger->pWhen);
  sqlite3IdListDelete(db, pTrigger->pColumns);
  sqlite3DbFree(db, pTrigger);
}

/*
** This function is called to drop a trigger from the database schema. 
................................................................................
  Table   *pTable;
  Vdbe *v;
  sqlite3 *db = pParse->db;
  int iDb;

  iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
  assert( iDb>=0 && iDb<db->nDb );
  sqlite3SchemaWritable(pParse, iDb);
  pTable = tableOfTrigger(pTrigger);
  assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
  if( pTable ){
    int code = SQLITE_DROP_TRIGGER;
    const char *zDb = db->aDb[iDb].zDbSName;
    const char *zTab = SCHEMA_TABLE(iDb);

Changes to src/vacuum.c.

121
122
123
124
125
126
127

128
129
130
131
132
133
134
    ** legacy applications. */
    iDb = sqlite3FindDb(pParse->db, pNm);
    if( iDb<0 ) iDb = 0;
#endif
  }
  if( iDb!=1 ){
    int iIntoReg = 0;

    if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){
      iIntoReg = ++pParse->nMem;
      sqlite3ExprCode(pParse, pInto, iIntoReg);
    }
    sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg);
    sqlite3VdbeUsesBtree(v, iDb);
  }







>







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
    ** legacy applications. */
    iDb = sqlite3FindDb(pParse->db, pNm);
    if( iDb<0 ) iDb = 0;
#endif
  }
  if( iDb!=1 ){
    int iIntoReg = 0;
    sqlite3SchemaWritable(pParse, iDb);
    if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){
      iIntoReg = ++pParse->nMem;
      sqlite3ExprCode(pParse, pInto, iIntoReg);
    }
    sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg);
    sqlite3VdbeUsesBtree(v, iDb);
  }

Changes to src/vdbe.c.

3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
....
3589
3590
3591
3592
3593
3594
3595







3596
3597
3598
3599
3600
3601
3602
    }
  }
  assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
  if( pOp->p5
   && (iMeta!=pOp->p3
      || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i)
  ){
    /*
    ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
    ** version is checked to ensure that the schema has not changed since the
    ** SQL statement was prepared.
    */
    sqlite3DbFree(db, p->zErrMsg);
    p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
    /* If the schema-cookie from the database file matches the cookie 
    ** stored with the in-memory representation of the schema, do
    ** not reload the schema from the database file.
    **
    ** If virtual-tables are in use, this is not just an optimization.
    ** Often, v-tables store their data in other SQLite tables, which
    ** are queried from within xNext() and other v-table methods using
................................................................................
    ** v-table would have to be ready for the sqlite3_vtab structure itself
    ** to be invalidated whenever sqlite3_step() is called from within 
    ** a v-table method.
    */
    if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
      sqlite3ResetOneSchema(db, pOp->p1);
    }







    p->expired = 1;
    rc = SQLITE_SCHEMA;
  }
  if( rc ) goto abort_due_to_error;
  break;
}








<
<
<
<
<
<
<







 







>
>
>
>
>
>
>







3566
3567
3568
3569
3570
3571
3572







3573
3574
3575
3576
3577
3578
3579
....
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
    }
  }
  assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
  if( pOp->p5
   && (iMeta!=pOp->p3
      || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i)
  ){







    /* If the schema-cookie from the database file matches the cookie 
    ** stored with the in-memory representation of the schema, do
    ** not reload the schema from the database file.
    **
    ** If virtual-tables are in use, this is not just an optimization.
    ** Often, v-tables store their data in other SQLite tables, which
    ** are queried from within xNext() and other v-table methods using
................................................................................
    ** v-table would have to be ready for the sqlite3_vtab structure itself
    ** to be invalidated whenever sqlite3_step() is called from within 
    ** a v-table method.
    */
    if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
      sqlite3ResetOneSchema(db, pOp->p1);
    }
    /*
    ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
    ** version is checked to ensure that the schema has not changed since the
    ** SQL statement was prepared.
    */
    sqlite3DbFree(db, p->zErrMsg);
    p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
    p->expired = 1;
    rc = SQLITE_SCHEMA;
  }
  if( rc ) goto abort_due_to_error;
  break;
}

Changes to src/vdbe.h.

219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
  void sqlite3ExplainBreakpoint(const char*,const char*);
#else
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);







|







219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
  void sqlite3ExplainBreakpoint(const char*,const char*);
#else
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif
void sqlite3VdbeAddParseSchemaOp(Parse*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);

Changes to src/vdbeaux.c.

467
468
469
470
471
472
473
474

475

476
477
478
479
480
481
482
** Add an OP_ParseSchema opcode.  This routine is broken out from
** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
** as having been used.
**
** The zWhere string must have been obtained from sqlite3_malloc().
** This routine will take ownership of the allocated memory.
*/
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){

  int j;

  sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
  for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
}

/*
** Add an opcode that includes the p4 value as an integer.
*/







|
>

>







467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
** Add an OP_ParseSchema opcode.  This routine is broken out from
** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
** as having been used.
**
** The zWhere string must have been obtained from sqlite3_malloc().
** This routine will take ownership of the allocated memory.
*/
void sqlite3VdbeAddParseSchemaOp(Parse *pParse, int iDb, char *zWhere){
  Vdbe *p = pParse->pVdbe;
  int j;
  sqlite3SchemaWritable(pParse, iDb);
  sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
  for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
}

/*
** Add an opcode that includes the p4 value as an integer.
*/

Changes to src/vdbeblob.c.

127
128
129
130
131
132
133

134

135
136
137
138
139
140
141
...
144
145
146
147
148
149
150

151
152
153
154
155

156
157
158
159
160
161
162
...
327
328
329
330
331
332
333


334
335
336
337
338
339
340
){
  int nAttempt = 0;
  int iCol;               /* Index of zColumn in row-record */
  int rc = SQLITE_OK;
  char *zErr = 0;
  Table *pTab;
  Incrblob *pBlob = 0;

  Parse sParse;


#ifdef SQLITE_ENABLE_API_ARMOR
  if( ppBlob==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  *ppBlob = 0;
................................................................................
    return SQLITE_MISUSE_BKPT;
  }
#endif
  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */

  sqlite3_mutex_enter(db->mutex);


  pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
  do {
    memset(&sParse, 0, sizeof(Parse));
    if( !pBlob ) goto blob_open_out;
    sParse.db = db;

    sqlite3DbFree(db, zErr);
    zErr = 0;

    sqlite3BtreeEnterAll(db);
    pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
    if( pTab && IsVirtual(pTab) ){
      pTab = 0;
................................................................................
    if( db->mallocFailed ){
      goto blob_open_out;
    }
    rc = blobSeekToRow(pBlob, iRow, &zErr);
  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );

blob_open_out:


  if( rc==SQLITE_OK && db->mallocFailed==0 ){
    *ppBlob = (sqlite3_blob *)pBlob;
  }else{
    if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
    sqlite3DbFree(db, pBlob);
  }
  sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);







>

>







 







>





>







 







>
>







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
){
  int nAttempt = 0;
  int iCol;               /* Index of zColumn in row-record */
  int rc = SQLITE_OK;
  char *zErr = 0;
  Table *pTab;
  Incrblob *pBlob = 0;
  Parse *pParentParse = db->pParse;
  Parse sParse;
  int bUnlock;            /* True to unlock reusable schemas before returning */

#ifdef SQLITE_ENABLE_API_ARMOR
  if( ppBlob==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  *ppBlob = 0;
................................................................................
    return SQLITE_MISUSE_BKPT;
  }
#endif
  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */

  sqlite3_mutex_enter(db->mutex);

  bUnlock = sqlite3LockReusableSchema(db);
  pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
  do {
    memset(&sParse, 0, sizeof(Parse));
    if( !pBlob ) goto blob_open_out;
    sParse.db = db;
    db->pParse = &sParse;
    sqlite3DbFree(db, zErr);
    zErr = 0;

    sqlite3BtreeEnterAll(db);
    pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
    if( pTab && IsVirtual(pTab) ){
      pTab = 0;
................................................................................
    if( db->mallocFailed ){
      goto blob_open_out;
    }
    rc = blobSeekToRow(pBlob, iRow, &zErr);
  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );

blob_open_out:
  db->pParse = pParentParse;
  sqlite3UnlockReusableSchema(db, bUnlock);
  if( rc==SQLITE_OK && db->mallocFailed==0 ){
    *ppBlob = (sqlite3_blob *)pBlob;
  }else{
    if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
    sqlite3DbFree(db, pBlob);
  }
  sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);

Changes to src/vtab.c.

188
189
190
191
192
193
194


















195
196
197
198
199
200
201
...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
...
559
560
561
562
563
564
565

566
567
568
569
570
571
572
...
575
576
577
578
579
580
581
582




583
584
585
586
587
588
589




590
591
592
593
594
595
596
...
625
626
627
628
629
630
631
632


633
634
635







636
637

638
639
640
641
642
643
644
...
683
684
685
686
687
688
689

690
691
692
693
694
695
696
** pTab is a pointer to a Table structure representing a virtual-table.
** Return a pointer to the VTable object used by connection db to access 
** this virtual-table, if one has been created, or NULL otherwise.
*/
VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
  VTable *pVtab;
  assert( IsVirtual(pTab) );


















  for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
  return pVtab;
}

/*
** Decrement the ref-count on a virtual table object. When the ref-count
** reaches zero, call the xDisconnect() method to delete the object.
................................................................................
      pParse->regRowid
    );
    v = sqlite3GetVdbe(pParse);
    sqlite3ChangeCookie(pParse, iDb);

    sqlite3VdbeAddOp0(v, OP_Expire);
    zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
    sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
    sqlite3DbFree(db, zStmt);

    iReg = ++pParse->nMem;
    sqlite3VdbeLoadString(v, iReg, pTab->zName);
    sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
  }

................................................................................
  int rc;
  const char *const*azArg = (const char *const*)pTab->azModuleArg;
  int nArg = pTab->nModuleArg;
  char *zErr = 0;
  char *zModuleName;
  int iDb;
  VtabCtx *pCtx;


  /* Check that the virtual-table is not already being initialized */
  for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
    if( pCtx->pTab==pTab ){
      *pzErr = sqlite3MPrintf(db, 
          "vtable constructor called recursively: %s", pTab->zName
      );
................................................................................
  }

  zModuleName = sqlite3DbStrDup(db, pTab->zName);
  if( !zModuleName ){
    return SQLITE_NOMEM_BKPT;
  }

  pVTable = sqlite3MallocZero(sizeof(VTable));




  if( !pVTable ){
    sqlite3OomFault(db);
    sqlite3DbFree(db, zModuleName);
    return SQLITE_NOMEM_BKPT;
  }
  pVTable->db = db;
  pVTable->pMod = pMod;




  pVTable->eVtabRisk = SQLITE_VTABRISK_Normal;

  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;

  /* Invoke the virtual table constructor */
  assert( &db->pVtabCtx );
................................................................................
      *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
      sqlite3VtabUnlock(pVTable);
      rc = SQLITE_ERROR;
    }else{
      int iCol;
      u16 oooHidden = 0;
      /* If everything went according to plan, link the new VTable structure
      ** into the linked list headed by pTab->pVTable. Then loop through the 


      ** columns of the table to see if any of them contain the token "hidden".
      ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from
      ** the type string.  */







      pVTable->pNext = pTab->pVTable;
      pTab->pVTable = pVTable;


      for(iCol=0; iCol<pTab->nCol; iCol++){
        char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
        int nType;
        int i = 0;
        nType = sqlite3Strlen30(zType);
        for(i=0; i<nType; i++){
................................................................................
  sqlite3 *db = pParse->db;
  const char *zMod;
  Module *pMod;
  int rc;

  assert( pTab );
  if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){

    return SQLITE_OK;
  }

  /* Locate the required virtual table module */
  zMod = pTab->azModuleArg[0];
  pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);








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







 







|







 







>







 







|
>
>
>
>







>
>
>
>







 







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







 







>







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
...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
...
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
...
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
...
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
** pTab is a pointer to a Table structure representing a virtual-table.
** Return a pointer to the VTable object used by connection db to access 
** this virtual-table, if one has been created, or NULL otherwise.
*/
VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
  VTable *pVtab;
  assert( IsVirtual(pTab) );
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  if( IsSharedSchema(db) ){
    int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    if( iDb!=1 ){
      VTable **pp;
      for(pp=&db->aDb[iDb].pVTable; *pp; pp=&(*pp)->pNext){
        if( sqlite3StrICmp(pTab->zName, (*pp)->zName)==0 ) break;
      }
      pVtab = *pp;
      if( pVtab && pTab->nCol<=0 ){
        *pp = pVtab->pNext;
        sqlite3VtabUnlock(pVtab);
        pVtab = 0;
      }
      return pVtab;
    }
  }
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
  for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
  return pVtab;
}

/*
** Decrement the ref-count on a virtual table object. When the ref-count
** reaches zero, call the xDisconnect() method to delete the object.
................................................................................
      pParse->regRowid
    );
    v = sqlite3GetVdbe(pParse);
    sqlite3ChangeCookie(pParse, iDb);

    sqlite3VdbeAddOp0(v, OP_Expire);
    zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
    sqlite3VdbeAddParseSchemaOp(pParse, iDb, zWhere);
    sqlite3DbFree(db, zStmt);

    iReg = ++pParse->nMem;
    sqlite3VdbeLoadString(v, iReg, pTab->zName);
    sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
  }

................................................................................
  int rc;
  const char *const*azArg = (const char *const*)pTab->azModuleArg;
  int nArg = pTab->nModuleArg;
  char *zErr = 0;
  char *zModuleName;
  int iDb;
  VtabCtx *pCtx;
  int nByte;                      /* Bytes of space to allocate */

  /* Check that the virtual-table is not already being initialized */
  for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
    if( pCtx->pTab==pTab ){
      *pzErr = sqlite3MPrintf(db, 
          "vtable constructor called recursively: %s", pTab->zName
      );
................................................................................
  }

  zModuleName = sqlite3DbStrDup(db, pTab->zName);
  if( !zModuleName ){
    return SQLITE_NOMEM_BKPT;
  }

  nByte = sizeof(VTable);
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  nByte += sqlite3Strlen30(pTab->zName) + 1;
#endif
  pVTable = (VTable*)sqlite3MallocZero(nByte);
  if( !pVTable ){
    sqlite3OomFault(db);
    sqlite3DbFree(db, zModuleName);
    return SQLITE_NOMEM_BKPT;
  }
  pVTable->db = db;
  pVTable->pMod = pMod;
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
  pVTable->zName = (char*)&pVTable[1];
  memcpy(pVTable->zName, pTab->zName, nByte-sizeof(VTable));
#endif
  pVTable->eVtabRisk = SQLITE_VTABRISK_Normal;

  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;

  /* Invoke the virtual table constructor */
  assert( &db->pVtabCtx );
................................................................................
      *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
      sqlite3VtabUnlock(pVTable);
      rc = SQLITE_ERROR;
    }else{
      int iCol;
      u16 oooHidden = 0;
      /* If everything went according to plan, link the new VTable structure
      ** into the linked list headed by pTab->pVTable. Or, if this is a
      ** reusable schema, into the linked list headed by Db.pVTable.
      **
      ** Then loop through the columns of the table to see if any of them
      ** contain the token "hidden". If so, set the Column COLFLAG_HIDDEN flag
      ** and remove the token from the type string.  */
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
      if( IsSharedSchema(db) && iDb!=1 ){
        pVTable->pNext = db->aDb[iDb].pVTable;
        db->aDb[iDb].pVTable = pVTable;
      }else
#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */
      {
        pVTable->pNext = pTab->pVTable;
        pTab->pVTable = pVTable;
      }

      for(iCol=0; iCol<pTab->nCol; iCol++){
        char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
        int nType;
        int i = 0;
        nType = sqlite3Strlen30(zType);
        for(i=0; i<nType; i++){
................................................................................
  sqlite3 *db = pParse->db;
  const char *zMod;
  Module *pMod;
  int rc;

  assert( pTab );
  if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
    assert( !IsVirtual(pTab) || pTab->nCol>0 );
    return SQLITE_OK;
  }

  /* Locate the required virtual table module */
  zMod = pTab->azModuleArg[0];
  pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);

Added test/reuse1.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
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
# 2017 August 9
#
# 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.
#
#***********************************************************************
#
#


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

ifcapable !sharedschema {
  finish_test
  return
}

forcedelete test.db2
sqlite3 db2 test.db2

do_execsql_test 1.0 {
  CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
  CREATE INDEX i1 ON t1(z);
  PRAGMA schema_version;
} {2}

do_execsql_test -db db2 1.1 {
  CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
  CREATE INDEX i1 ON t1(z);
  PRAGMA schema_version;
} {2}

do_test 1.2 {
  db close
  db2 close
  sqlite3 db2 test.db2 -shared-schema 1
  sqlite3 db  test.db -shared-schema 1
} {}

do_execsql_test -db db2 1.3.1 {
  INSERT INTO t1 VALUES(1, 2, 3);
  INSERT INTO t1 VALUES(4, 5, 6);
}

do_execsql_test 1.3.2 {
  SELECT * FROM t1;
  PRAGMA integrity_check;
} {ok}

do_execsql_test -db db2 1.3.3 {
  SELECT * FROM t1;
  PRAGMA integrity_check;
} {1 2 3 4 5 6 ok}

sqlite3 db3 test.db2
do_execsql_test -db db3 1.4.1 {
  ALTER TABLE t1 ADD COLUMN a;
}
do_execsql_test -db db2 1.4.2 {
  SELECT * FROM t1;
} {1 2 3 {} 4 5 6 {}}
do_execsql_test 1.4.3 {
  SELECT * FROM t1;
} {}

db3 close
sqlite3 db3 test.db
do_execsql_test -db db3 1.5.0 {
  CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
    SELECT 1, 2, 3;
  END;
}

# Check that the schema cannot be modified if the db was opened with
# SQLITE_OPEN_REUSE_SCHEMA.
#
foreach {tn sql} {
  1  { CREATE TABLE t2(x, y) }
  2  { CREATE INDEX i2 ON t1(z) }
  3  { CREATE VIEW v2 AS SELECT * FROM t2 }
  4  { ALTER TABLE t1 RENAME TO t3 }
  5  { ALTER TABLE t1 ADD COLUMN xyz }
  6  { VACUUM }
  7  { DROP INDEX i1 }
  8  { DROP TABLE t1 }
  9  { DROP TRIGGER tr1 }
  10 { ANALYZE }
  11 { ALTER TABLE t1 RENAME z TO zzz }
} {
  do_catchsql_test 1.5.$tn $sql {1 {attempt to modify read-only schema}}
}

#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
ifcapable fts5 {
  do_execsql_test 2.0 {
    CREATE VIRTUAL TABLE ft USING fts5(a);
    INSERT INTO ft VALUES('one'), ('two'), ('three');
    ATTACH 'test.db2' AS aux;
    CREATE VIRTUAL TABLE aux.ft USING fts5(a);
    INSERT INTO aux.ft VALUES('aux1'), ('aux2'), ('aux3');
  }

  db close
  sqlite3 db  test.db -shared-schema 1

  do_execsql_test 2.1 {
    ATTACH 'test.db2' AS aux;
    SELECT * FROM main.ft;
  } {one two three}

breakpoint
  do_execsql_test 2.2 {
    SELECT * FROM aux.ft;
  } {aux1 aux2 aux3}

  do_execsql_test 2.2 {
    SELECT * FROM aux.ft_content;
  } {1 aux1 2 aux2 3 aux3}
}

#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
do_execsql_test 3.0 {
  CREATE TABLE t1(a PRIMARY KEY, b, c);
  CREATE VIEW v1 AS SELECT * FROM t1;
  CREATE TRIGGER v1_ins INSTEAD OF INSERT ON v1 BEGIN
    INSERT INTO t1 VALUES(new.a, new.b, new.c);
  END;
  CREATE TRIGGER v1_del INSTEAD OF DELETE ON v1 BEGIN
    DELETE FROM t1 WHERE a=old.a;
  END;
  CREATE TRIGGER v1_up INSTEAD OF UPDATE ON v1 BEGIN
    UPDATE t1 SET a=new.a, b=new.b, c=new.c WHERE a=old.a;
  END;
}
forcecopy test.db test.db2

do_test 3.1 {
  sqlite3 db2 test.db2
  execsql { INSERT INTO t1 VALUES(1, 2, 3) } db
  execsql { INSERT INTO t1 VALUES(4, 5, 6) } db2
  db2 close
  execsql { ATTACH 'test.db2' AS aux; }
} {}

do_execsql_test 3.2 {
  SELECT * FROM main.v1;
} {1 2 3}

do_execsql_test 3.3 {
  SELECT * FROM aux.v1;
} {4 5 6}

db close
sqlite3 db test.db -shared-schema 1

do_execsql_test 3.4 { ATTACH 'test.db2' AS aux } {}
do_execsql_test 3.5 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.6 { SELECT * FROM aux.v1  } {4 5 6}

do_execsql_test 3.7.1 { INSERT INTO aux.t1 VALUES(8, 9, 10); }
do_execsql_test 3.7.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.7.3 { SELECT * FROM aux.v1  } {4 5 6 8 9 10}

do_execsql_test 3.8.1 { DELETE FROM aux.t1 WHERE b=5 }
do_execsql_test 3.8.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.8.3 { SELECT * FROM aux.v1  } {8 9 10}

do_execsql_test 3.9.1 { UPDATE aux.t1 SET b='abc' }
do_execsql_test 3.9.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.9.3 { SELECT * FROM aux.v1  } {8 abc 10}

do_execsql_test 3.10.1 { INSERT INTO aux.v1 VALUES(11, 12, 13) }
do_execsql_test 3.10.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.10.3 { SELECT * FROM aux.v1  } {8 abc 10 11 12 13}

do_execsql_test 3.11.1 { DELETE FROM aux.v1 WHERE b='abc' }
do_execsql_test 3.11.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.11.3 { SELECT * FROM aux.v1  } {11 12 13}

do_execsql_test 3.12.1 { UPDATE aux.v1 SET b='def' }
do_execsql_test 3.12.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.12.3 { SELECT * FROM aux.v1  } {11 def 13}

do_execsql_test 3.13.1 {
  CREATE TEMP TRIGGER xyz AFTER INSERT ON aux.t1 BEGIN
    INSERT INTO v1 VALUES(new.a, new.b, new.c);
  END
}
do_execsql_test 3.13.2 {
  INSERT INTO aux.v1 VALUES('x', 'y', 'z');
}
do_execsql_test 3.13.3 {
  SELECT * FROM v1;
} {1 2 3 x y z}

#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
do_execsql_test 4.0 {
  CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE);
  CREATE TABLE del(a, b, c);
  CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
    INSERT INTO del VALUES(old.a, old.b, old.c);
  END;
}
forcecopy test.db test.db2

db close
sqlite3 db test.db -shared-schema 1
execsql { 
  ATTACH 'test.db2' AS aux;
  PRAGMA recursive_triggers = 1;
}

do_execsql_test 4.1 {
  INSERT INTO main.t1 VALUES(1, 2, 3);
  INSERT INTO aux.t1 VALUES(4, 5, 6);
}

do_execsql_test 4.2.1 {
  INSERT OR REPLACE INTO aux.t1 VALUES('a', 'b', 6);
  SELECT * FROM aux.t1;
} {a b 6}
do_execsql_test 4.2.2 { SELECT * FROM aux.del  } {4 5 6}
do_execsql_test 4.2.3 { SELECT * FROM main.del } {}

do_execsql_test 4.3.1 {
  INSERT INTO aux.t1 VALUES('x', 'y', 'z');
  UPDATE OR REPLACE aux.t1 SET c='z' WHERE a='a';
} {}
do_execsql_test 4.3.2 { SELECT * FROM aux.del  } {4 5 6 x y z}
do_execsql_test 4.3.3 { SELECT * FROM main.del } {}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
  CREATE INDEX i1 ON t1(b);
  INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6);
  ANALYZE;
  PRAGMA writable_schema = 1;
  DELETE FROM sqlite_stat1;
}
db close
forcecopy test.db test.db2
sqlite3 db test.db -shared-schema 1
execsql { ATTACH 'test.db2' AS aux }

foreach {tn sql} {
  1 { CREATE TABLE t3(x) }
  2 { DROP TABLE t2 }
  3 { CREATE INDEX i2 ON t2(b) }
  4 { DROP INDEX i1 }
  5 { ALTER TABLE t1 ADD COLUMN d }
  6 { ALTER TABLE t1 RENAME TO t3 }
  7 { ALTER TABLE t1 RENAME c TO d }
} {
  do_catchsql_test 5.1.$tn $sql {1 {attempt to modify read-only schema}}
}

do_execsql_test 5.2.1 { ANALYZE aux.t1 } {}
do_execsql_test 5.2.2 { SELECT * FROM aux.sqlite_stat1  } {t1 i1 {2 1}}
do_execsql_test 5.2.3 { SELECT * FROM main.sqlite_stat1 } {}

do_test 5.3.0 {
  sqlite3 db2 test.db2
  db2 eval { 
    PRAGMA writable_schema = 1;
    DELETE FROM sqlite_stat1;
  }
} {}

do_execsql_test 5.3.1 { SELECT * FROM aux.sqlite_stat1  } {}
do_execsql_test 5.3.2 { ANALYZE aux } {}
do_execsql_test 5.3.3 { SELECT * FROM aux.sqlite_stat1  } {t1 i1 {2 1}}
do_execsql_test 5.3.4 { SELECT * FROM main.sqlite_stat1 } {}

#-------------------------------------------------------------------------
# Attempting to run ANALYZE when the required sqlite_statXX functions
# are missing is an error (because it would modify the database schema).
#
reset_db
do_execsql_test 5.4 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
  CREATE INDEX i1 ON t1(b);
  INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6);
}
db close
sqlite3 db test.db -shared-schema 1
foreach {tn sql} {
  1 { ANALYZE }
  2 { ANALYZE t1 }
  3 { ANALYZE i1 }
  4 { ANALYZE main }
  5 { ANALYZE main.t1 }
  6 { ANALYZE main.i1 }
} {
  do_catchsql_test 5.4.$tn $sql {1 {attempt to modify read-only schema}}
}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 6.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
  CREATE VIEW v1 AS SELECT * FROM t1;
}
db close
forcecopy test.db test.db2
sqlite3 db test.db -shared-schema 1
execsql { ATTACH 'test.db2' AS aux }

do_execsql_test 6.1 {
  INSERT INTO main.t1(a) VALUES(1), (2), (3);
  INSERT INTO aux.t1(a) VALUES(4), (5), (6);
  CREATE TEMP TABLE t2(i,t);
  INSERT INTO t2 VALUES(2, 'two'), (5, 'five');
}

do_execsql_test 6.2 {
  SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.t1)
} {five}
do_execsql_test 6.3 {
  SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.v1)
} {five}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 7.0 {
  CREATE TABLE p1(a PRIMARY KEY, b);
  CREATE TABLE p2(a PRIMARY KEY, b);
  CREATE TABLE c1(x REFERENCES p1 ON UPDATE CASCADE ON DELETE CASCADE);
}

db close
forcecopy test.db test.db2
sqlite3 db test.db -shared-schema 1
execsql { ATTACH 'test.db2' AS aux }

do_execsql_test 7.1 {
  INSERT INTO aux.p1 VALUES(1, 'one');
  INSERT INTO aux.p1 VALUES(2, 'two');
  PRAGMA foreign_keys = on;
}

do_execsql_test 7.2 {
  INSERT INTO aux.c1 VALUES(2);
}

do_execsql_test 7.3.1 {
  PRAGMA foreign_keys = off;
  INSERT INTO main.p2 SELECT * FROM aux.p1;
}
do_execsql_test 7.3.2 {
  SELECT * FROM main.p2;
} {1 one 2 two}

do_execsql_test 7.3.3 {
  INSERT INTO aux.p2 VALUES(1, 2);
}

do_execsql_test 7.3.4 {
  SELECT main.p2.a FROM main.p2, aux.p2;
} {1 2}

do_execsql_test 7.3.5 {
  SELECT * FROM main.p2, aux.p2;
} {1 one 1 2   2 two 1 2}

do_execsql_test 7.4 {
  SELECT count(*) FROM aux.p2;
} {1}


finish_test


Added test/reuse2.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
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
# 2017 August 9
#
# 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.
#
#***********************************************************************
#
#


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

ifcapable !sharedschema {
  finish_test
  return
}

do_execsql_test 1.0 {
  CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
  CREATE INDEX i1 ON t1(z);
  PRAGMA schema_version;
} {2}

do_test 1.2 {
  catch { db close }
  catch { db2 close }
  sqlite3 db2 test.db -shared-schema 1
  sqlite3 db  test.db -shared-schema 1
} {}

do_execsql_test -db db2 1.3.1 {
  INSERT INTO t1 VALUES(1, 2, 3);
}

do_execsql_test -db db2 1.3.2 {
  INSERT INTO t1 VALUES(4, 5, 6);
}

do_execsql_test 1.3.3 {
  SELECT * FROM t1;
} {1 2 3 4 5 6}

#--------------------------------------------------------------------------
reset_db
ifcapable fts5 {
  do_execsql_test 2.0 {
    CREATE VIRTUAL TABLE ft USING fts5(c);
    INSERT INTO ft VALUES('one two three');
  }
  db close
  sqlite3 db test.db -shared-schema 1

  do_execsql_test 2.1 {
    SELECT * FROM ft
  } {{one two three}}
}

#--------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
  CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
  CREATE INDEX i1 ON t1(z);
  PRAGMA schema_version;
} {2}

do_test 3.1 {
  sqlite3 db1 test.db -shared-schema 1
  sqlite3 db2 test.db -shared-schema 1
} {}

do_execsql_test -db db1 3.2.1 { SELECT * FROM t1 }
do_execsql_test -db db2 3.2.2 { SELECT * FROM t1 }

register_schemapool_module db
do_execsql_test 3.3 { 
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=2 nschema=1 ndelete=0}

sqlite3 db3 test.db -shared-schema 1
register_schemapool_module db3

do_execsql_test 3.5 { 
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=2 nschema=1 ndelete=0}

do_execsql_test -db db3 3.6 { 
  SELECT * FROM t1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=3 nschema=1 ndelete=0}

do_execsql_test 3.7 { 
  CREATE TABLE t2(x);
}

do_execsql_test 3.8 { 
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=3 nschema=1 ndelete=0}

do_execsql_test -db db1 3.9.1 { SELECT * FROM t1 }
do_execsql_test 3.9.2 { 
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=1 nschema=1 ndelete=0 nref=2 nschema=1 ndelete=0}

do_execsql_test -db db2 3.10.1 { SELECT * FROM t1 }
do_execsql_test 3.10.2 { 
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool ORDER BY 1;
} {nref=1 nschema=1 ndelete=0 nref=2 nschema=1 ndelete=0}

do_execsql_test -db db3 3.11.1 { SELECT * FROM t1 }
do_execsql_test 3.11.2 { 
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=3 nschema=1 ndelete=0}

#--------------------------------------------------------------------------
catch {db1 close}
catch {db2 close}
catch {db3 close}
reset_db
do_execsql_test 4.0.1 {
  CREATE TABLE x1(a, b, c);
  CREATE INDEX x1a ON x1(a);
  CREATE INDEX x1b ON x1(b);
}
do_test 4.0.2 {
  db close
  for {set i 1} {$i < 6} {incr i} {
    forcedelete test.db${i}-journal test.db${i}-wal test.db${i}-wal2 
    forcecopy test.db test.db${i}
  }
  sqlite3 db  test.db
  sqlite3 db2 test.db -shared-schema 1
} {}

register_schemapool_module db
do_execsql_test 4.0.3 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {}

do_test 4.1.1 {
  execsql { 
    ATTACH 'test.db1' AS db1; 
    ATTACH 'test.db2' AS db2;
    ATTACH 'test.db3' AS db3;
    ATTACH 'test.db4' AS db4;
    ATTACH 'test.db5' AS db5;
  } db2
} {}
do_execsql_test 4.1.2 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {}
do_execsql_test -db db2 4.1.3 {
  SELECT * FROM db3.x1
}
do_execsql_test 4.1.4 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=1 nschema=1 ndelete=0}
do_execsql_test -db db2 4.1.5 {
  SELECT * FROM db2.x1
}
do_execsql_test 4.1.6 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=2 nschema=1 ndelete=0}
do_execsql_test -db db2 4.1.7 {
  SELECT * FROM x1
}
do_execsql_test 4.1.8 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=6 nschema=1 ndelete=0}

do_test 4.2.1 {
  catchsql { SELECT * FROM abc } db2
} {1 {no such table: abc}}
do_execsql_test 4.2.2 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=6 nschema=1 ndelete=0}

register_schemapool_module db2
do_execsql_test -db db2 4.3.1 {
  INSERT INTO x1 VALUES(1, 2, 3);
  INSERT INTO db1.x1 VALUES(4, 5, 6);
  INSERT INTO db2.x1 VALUES(7, 8, 9);
  INSERT INTO db3.x1 VALUES(10, 11, 12);
  INSERT INTO db4.x1 VALUES(13, 14, 15);
  INSERT INTO db5.x1 VALUES(16, 17, 18);
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=6 nschema=1 ndelete=0}

do_execsql_test -db db2 4.3.2 {
  SELECT * FROM db5.x1;
  SELECT * FROM db4.x1;
  SELECT * FROM db3.x1;
  SELECT * FROM db2.x1;
  SELECT * FROM db1.x1;
  SELECT * FROM x1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {
  16 17 18  13 14 15  10 11 12  7 8 9  4 5 6  1 2 3
  nref=6 nschema=1 ndelete=0
}

do_execsql_test -db db2 4.3.3 {
  UPDATE x1 SET a=a+10;
  UPDATE db5.x1 SET a=a+10;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {
  nref=6 nschema=1 ndelete=0
}

do_execsql_test -db db2 4.3.4 {
  SELECT * FROM db5.x1;
  SELECT * FROM db4.x1;
  SELECT * FROM db3.x1;
  SELECT * FROM db2.x1;
  SELECT * FROM db1.x1;
  SELECT * FROM x1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {
  26 17 18  13 14 15  10 11 12  7 8 9  4 5 6  11 2 3
  nref=6 nschema=1 ndelete=0
}

do_execsql_test -db db2 4.3.5 {
  DELETE FROM db3.x1;
  DELETE FROM x1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {
  nref=6 nschema=1 ndelete=0
}

do_execsql_test -db db2 4.3.6 {
  SELECT * FROM db5.x1;
  SELECT * FROM db4.x1;
  SELECT * FROM db3.x1;
  SELECT * FROM db2.x1;
  SELECT * FROM db1.x1;
  SELECT * FROM x1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {
  26 17 18  13 14 15  7 8 9  4 5 6 
  nref=6 nschema=1 ndelete=0
}

do_execsql_test -db db2 4.3.6 {
  SELECT * FROM db5.x1, db4.x1, db1.x1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {26 17 18 13 14 15 4 5 6 nref=6 nschema=3 ndelete=0}

#--------------------------------------------------------------------------
# Test the incremental-blob API with REUSE_SCHEMA connections.
#
catch {db1 close}
catch {db2 close}
catch {db3 close}
reset_db
do_execsql_test 5.0.1 {
  CREATE TABLE bbb(a INTEGER PRIMARY KEY, b);
}
db close
do_test 5.0.2 {
  sqlite3 db2 test.db -shared-schema 1
  register_schemapool_module db2
  for {set i 1} {$i<6} {incr i} {
    forcedelete test.db${i}-journal test.db${i}-wal test.db${i}-wal2 
    forcecopy test.db test.db${i}
    sqlite3 db test.db${i}
    db eval { INSERT INTO bbb VALUES(123, 'database_' || $i) }
    db close
    db2 eval "ATTACH 'test.db${i}' AS db${i}"
  }
  execsql {
    SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
      FROM schemapool;
  } db2
} {nref=6 nschema=1 ndelete=0}

do_test 5.1.1 {
  set res [list]
  for {set i 1} {$i<6} {incr i} {
    set chan [db2 incrblob db${i} bbb b 123]
    lappend res [gets $chan]
    close $chan
  }
  set res
} {database_1 database_2 database_3 database_4 database_5}

do_execsql_test -db db2 5.1.2 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=6 nschema=1 ndelete=0}

do_test 5.2.1 {
  sqlite3_table_column_metadata db2 main bbb a
} {INTEGER BINARY 0 1 0}
do_test 5.2.2 {
  sqlite3_table_column_metadata db2 main bbb b
} {{} BINARY 0 0 0}

do_execsql_test -db db2 5.2.3 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {nref=6 nschema=1 ndelete=0}

do_execsql_test -db db2 5.2.4 {
  PRAGMA integrity_check;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete
  FROM schemapool;
} {ok nref=6 nschema=1 ndelete=5}

finish_test

Added test/reuse3.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
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
# 2019 February 12
#
# 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.
#
#***********************************************************************
#
#


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

ifcapable !sharedschema {
  finish_test
  return
}

do_execsql_test 1.0 {
  CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
  CREATE INDEX i1 ON t1(z);
  CREATE TABLE t2(a);
} {}

db close
sqlite3 db test.db -shared-schema 1

do_execsql_test 1.1 {
  CREATE TEMP VIEW v1 AS SELECT * FROM t1;
  SELECT * FROM v1;
}

do_execsql_test 1.2 {
  CREATE TEMP TRIGGER tr1 AFTER INSERT ON t1 BEGIN
    INSERT INTO t2 VALUES(new.x);
  END;
}

do_execsql_test 1.3 {
  INSERT INTO t1 VALUES(1, 2, 3);
}

do_execsql_test 1.4 {
  SELECT * FROM t2
} {1}

do_execsql_test 1.5 {
  SELECT * FROM v1
} {1 2 3}

do_execsql_test 1.6 {
  BEGIN;
    DROP TRIGGER tr1;
  ROLLBACK;
}

do_execsql_test 1.7 {
  SELECT * FROM v1
} {1 2 3}

do_execsql_test 1.8 {
  INSERT INTO t1 VALUES(4, 5, 6);
  SELECT * FROM t2
} {1 4}

do_execsql_test 1.9 {
  SELECT * FROM v1
} {1 2 3 4 5 6}

#-------------------------------------------------------------------------
# Test error messages when parsing the schema with a REUSE_SCHEMA 
# connection.
reset_db
do_execsql_test 2.0 {
  CREATE TABLE x1(a, b, c);
  CREATE TABLE y1(d, e, f);
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master SET sql = 'CREATE TBL y1(d, e, f)' WHERE name = 'y1';
}
db close

sqlite3 db test.db -shared-schema 1
do_catchsql_test 2.1 {
  SELECT * FROM x1;
} {1 {malformed database schema (y1) - near "TBL": syntax error}}

do_catchsql_test 2.2 {
  SELECT * FROM x1;
} {1 {malformed database schema (y1) - near "TBL": syntax error}}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
  CREATE TABLE x1(a, b, c);
  CREATE INDEX i1 ON x1(a, b, c);
  CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
    SELECT 1, 2, 3, 4, 5;
  END;
  INSERT INTO x1 VALUES(1, 2, 3);
}
sqlite3 db1 test.db -shared-schema 1

do_test 3.1 {
  execsql { SELECT * FROM x1 } db1
  set N [lindex [sqlite3_db_status db1 SCHEMA_USED 0] 1]
  expr $N==$N
} 1

sqlite3 db2 test.db -shared-schema 1
do_test 3.2 {
  execsql { SELECT * FROM x1 } db2
  set N2 [lindex [sqlite3_db_status db2 SCHEMA_USED 0] 1]
  expr $N2>($N/2) && $N2<($N/2)+400
} 1

sqlite3 db3 test.db -shared-schema 1
sqlite3 db4 test.db -shared-schema 1
do_test 3.3 {
  execsql { SELECT * FROM x1 } db3
  execsql { SELECT * FROM x1 } db4
  set N4 [lindex [sqlite3_db_status db2 SCHEMA_USED 0] 1]
  set M [expr 2*($N-$N2)]
  set {} {}
} {}
do_test 3.3.1 { expr {(($M / 4) + $N-$M)} } "#/$N4/"

catch { db1 close }
catch { db2 close }
catch { db3 close }
catch { db4 close }

#-------------------------------------------------------------------------
# 4.1 Test the REINDEX command.
# 4.2 Test CREATE TEMP ... commands.
#
reset_db
do_execsql_test 4.1.0 {
  CREATE TABLE x1(a, b, c);
  CREATE INDEX x1a ON x1(a);
  CREATE INDEX x1b ON x1(b);
  CREATE INDEX x1c ON x1(c);
}
db close
sqlite3 db test.db -shared-schema 1

do_execsql_test 4.1.1 {
  REINDEX x1;
  REINDEX x1a;
  REINDEX x1b;
  REINDEX x1c;
  REINDEX;
}

do_test 4.1.2 {
  for {set i 1} {$i < 5} {incr i} {
    forcedelete test.db${i} test.db${i}-wal test.db${i}-journal
    forcecopy test.db test.db${i}
    execsql "ATTACH 'test.db${i}' AS db${i}"
  }
  register_schemapool_module db
  set {} {}
  execsql { 
    SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool 
  }
} {nref=5 nschema=1 ndelete=0}

do_execsql_test 4.1.3 {
  REINDEX  x1;
  REINDEX  x1a;
  REINDEX  x1b;
  REINDEX  x1c;
  REINDEX  db1.x1a;
  REINDEX  db2.x1b;
  REINDEX  db3.x1c;
}

do_execsql_test 4.1.4 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool 
} {nref=5 nschema=1 ndelete=28}

#-------------------------------------------------------------------------
db close
sqlite3 db test.db -shared-schema 1
register_schemapool_module db
do_execsql_test 4.2.0 {
  ATTACH 'test.db1' AS db1;
  ATTACH 'test.db2' AS db2;
  ATTACH 'test.db3' AS db3;
  ATTACH 'test.db4' AS db4;

  SELECT * FROM db1.x1;
  SELECT * FROM db2.x1;
  SELECT * FROM db3.x1;
  SELECT * FROM db4.x1;
}

do_execsql_test 4.2.1 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool; 
} {nref=5 nschema=1 ndelete=0}

do_execsql_test 4.2.2 {
  CREATE TEMP TABLE t1(a, b, c);
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool; 
} {nref=5 nschema=1 ndelete=0}

do_execsql_test 4.2.3 {
  CREATE INDEX t1a ON t1(a);
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool; 
} {nref=5 nschema=1 ndelete=0}

do_execsql_test 4.2.4 {
  CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
    SELECT 1,2,3,4;
  END;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool; 
} {nref=5 nschema=1 ndelete=0}

do_execsql_test 4.2.5 {
  DROP TABLE t1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool; 
} {nref=5 nschema=1 ndelete=0}

do_execsql_test 4.2.6 {
  CREATE TEMP TRIGGER tr1 AFTER INSERT ON db2.x1 BEGIN
    SELECT 1,2,3,4;
  END;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool; 
} {nref=5 nschema=1 ndelete=0}

do_execsql_test 4.2.7 {
  DROP TRIGGER tr1;
  SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete 
    FROM schemapool; 
} {nref=5 nschema=1 ndelete=4}

#--------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t1(a, b);
  CREATE TABLE t2(a, b);
  CREATE TABLE t3(a, b);
}

sqlite3 db2 test.db -shared-schema 1
register_schemapool_module db2

do_execsql_test 5.1 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master SET sql='CREATE TABLE t3 a,b' WHERE name = 't3';
}

do_test 5.2 { 
  catchsql { SELECT * FROM t1 } db2
} {1 {malformed database schema (t3) - near "a": syntax error}}

do_test 5.3 { 
  catchsql { SELECT nref,nschema FROM schemapool } db2
} {1 {vtable constructor failed: schemapool}}

do_execsql_test 5.4 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master SET sql='CREATE TABLE t3(a,b)' WHERE name = 't3';
}

do_test 5.5 { 
  catchsql { SELECT nref,nschema FROM schemapool } db2
} {0 {1 1}}

db2 close
db close
do_test 5.6.1 {
  forcedelete test.db2 test.db2-wal test.db2-journal
  forcecopy test.db test.db2
  sqlite3 db test.db
  sqlite3 db2 test.db  -shared-schema 1
  sqlite3 db3 test.db2 -shared-schema 1
  register_schemapool_module db
} {}

do_execsql_test -db db2 5.6.2 { SELECT * FROM t1 }
do_execsql_test -db db3 5.6.3 { SELECT * FROM t1 }
do_execsql_test 5.6.4 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool; 
  CREATE TABLE t4(x);
  DROP TABLE t4;
} {nref=2 nschema=1}
do_execsql_test -db db2 5.6.5 { SELECT * FROM t1 }
do_execsql_test -db db3 5.6.6 { SELECT * FROM t1 }
do_execsql_test 5.6.7 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool; 
  ATTACH 'test.db2' AS db2;
  CREATE TABLE db2.t4(x);
  DROP TABLE db2.t4;
} {nref=1 nschema=1 nref=1 nschema=1}
do_execsql_test -db db2 5.6.8 { SELECT * FROM t1 }
do_execsql_test -db db3 5.6.9 { SELECT * FROM t1 }
do_execsql_test 5.6.10 {
  SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool; 
} {nref=2 nschema=1}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
  CREATE TABLE t1(a, b);
  CREATE TABLE t2(a, b);
  CREATE TABLE t3(a, b);
}

do_test 6.1 {
  db close
  sqlite3 db test.db -shared-schema 1
  for {set i 1} {$i < 5} {incr i} {
    set base "test.db$i"
    set nm "aux$i"
    forcedelete $base $base-wal $base-journal
    forcecopy test.db $base
    execsql "ATTACH '$base' AS $nm"
  }
} {}

do_test 6.2 {
  set N1 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
  set N2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
  expr ($N1==0 && $N2==0)
} {1}

do_test 6.3 {
  execsql { SELECT * FROM main.t1 }
  set N1 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
  set N2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
  expr {$N1>0 && $N2>0 && $N1==$N2}
} {1}

do_test 6.4 {
  execsql { SELECT * FROM aux1.t1 }
  set N3 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
  set N4 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
  list $N3 $N4
} "#/$N1 $N1/"

finish_test

Added test/reuse4.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
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
# 2019 February 12
#
# 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.
#
#***********************************************************************
#
#

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

ifcapable !sharedschema {
  finish_test
  return
}

foreach {tn sharedschema} {
  1 0  
  2 1  
} {
  reset_db

  do_execsql_test 1.$tn.0 {
    CREATE TABLE x1(a, b);
    CREATE INDEX x1a ON x1(a);
    CREATE INDEX x1b ON x1(b);
    CREATE TABLE x2(a, b);
  }
  db close
  
  do_test 1.$tn.1 {
    for {set i 1} {$i<4} {incr i} {
      forcedelete test.db$i test.db$i-journal test.db$i-wal
      forcecopy test.db test.db$i
    }
  
    sqlite3 db test.db -shared-schema $sharedschema
    for {set i 1} {$i<4} {incr i} {
      execsql " ATTACH 'test.db$i' AS db$i "
    }
  } {}
  
  do_execsql_test 1.$tn.2 {
    WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10 )
    INSERT INTO x1 SELECT i, i FROM s;
  
    INSERT INTO db3.x2 SELECT * FROM x1;
    INSERT INTO db2.x1 SELECT * FROM db3.x2;
    CREATE TEMP TRIGGER tr1 AFTER INSERT ON db2.x2 BEGIN
      INSERT INTO x1 VALUES(new.a, new.b);
    END;
    INSERT INTO db2.x2 SELECT * FROM x1 WHERE a%2;
    DELETE FROM x1 WHERE a<3;
    INSERT INTO db3.x1 SELECT * FROM db2.x2;
  
    DETACH db3;
    ATTACH 'test.db3' AS db3;
  
    UPDATE db3.x1 SET a=a-10 WHERE b NOT IN (SELECT b FROM db2.x2);
  
    CREATE TEMP TABLE x1(a, b);
    INSERT INTO db2.x2 VALUES(50, 60), (60, 70), (80, 90);
    ALTER TABLE x1 RENAME TO x2;
    ALTER TABLE x2 ADD COLUMN c;
    ALTER TABLE x2 RENAME a TO aaa;
    DELETE FROM x1 WHERE b>8;
    UPDATE db3.x2 SET b=b*10;
  
    BEGIN;
      CREATE TEMP TABLE x5(x);
      INSERT INTO x5 VALUES(1);
    ROLLBACK;
  
    INSERT INTO main.x2 VALUES(123, 456);
  }
  
  integrity_check 1.$tn.3
  
  do_execsql_test 1.$tn.4 {
    SELECT * FROM main.x1; SELECT 'xxx';
    SELECT * FROM main.x2; SELECT 'xxx';
    SELECT * FROM temp.x2; SELECT 'xxx';
  
    SELECT * FROM db1.x1; SELECT 'xxx';
    SELECT * FROM db1.x2; SELECT 'xxx';
    SELECT * FROM db2.x1; SELECT 'xxx';
    SELECT * FROM db2.x2; SELECT 'xxx';
    SELECT * FROM db3.x1; SELECT 'xxx';
    SELECT * FROM db3.x2; SELECT 'xxx';
  } {
    3 3 4 4 5 5 6 6 7 7 8 8 3 3 5 5 7 7 xxx 
    123 456 xxx 
    50 60 {} 60 70 {} 80 90 {} xxx
    xxx
    xxx
    1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 xxx
    1 1 3 3 5 5 7 7 9 9 50 60 60 70 80 90 xxx
    1 1 3 3  5 5 7 7 9 9 xxx 
    1 10 2 20 3 30 4 40 5 50 6 60 7 70 8 80 9 90 10 100 xxx
  }
  
  do_test 1.$tn.5.1 {
    sqlite3 db2 test.db
    db2 eval { CREATE TABLE x3(x) }
  } {}
  do_execsql_test 1.$tn.5.2 {
    SELECT * FROM main.x1; SELECT 'xxx';
    SELECT * FROM main.x2; SELECT 'xxx';
    SELECT * FROM main.x3; SELECT 'xxx';
  } {
    3 3 4 4 5 5 6 6 7 7 8 8 3 3 5 5 7 7 xxx 
    123 456 xxx 
    xxx
  }
}

#-------------------------------------------------------------------------
# Test some PRAGMA statements with shared-schema connections.
#
reset_db
do_execsql_test 2.0 {
  CREATE TABLE t1(a, b, c);
  CREATE INDEX t1abc ON t1(a, b, c);
}

foreach {tn pragma nSchema nDelete} {
  1 "PRAGMA synchronous = OFF"     1 0
  2 "PRAGMA cache_size = 200"      1 0
  3 "PRAGMA aux2.integrity_check"  1 0
  4 "PRAGMA      integrity_check"  1 5
  5 "PRAGMA index_info=t1abc"      1 5
  6 "PRAGMA aux3.index_info=t1abc" 1 0
  7 "PRAGMA journal_mode"          1 0
  8 "PRAGMA aux2.wal_checkpoint"   1 0
  9 "PRAGMA wal_checkpoint"        1 0
} {
  do_test 2.$tn.1 {
    catch { db close }
    catch { db2 close }
    for {set i 1} {$i < 6} {incr i} {
      forcedelete "test.db$i" "test.db${i}-wal" "test.db${i}-journal"
      forcecopy test.db test.db$i
    }
    sqlite3 db2 test.db -shared-schema 1
    for {set i 1} {$i < 6} {incr i} {
      execsql "ATTACH 'test.db$i' AS aux$i" db2
    }
  } {}

  sqlite3 db test.db
  register_schemapool_module db

  do_test 2.$tn.2 {
    execsql $pragma db2
    execsql { SELECT 'nschema='||nschema, 'ndelete='||nDelete FROM schemapool }
  } "nschema=$nSchema ndelete=$nDelete"

  do_test 2.$tn.3 {
    execsql {
      SELECT * FROM main.t1,aux1.t1,aux2.t1,aux3.t1,aux4.t1,aux5.t1
    } db2
    execsql { SELECT 'nschema=' || nschema, 'nref=' || nref FROM schemapool }
  } "nschema=6 nref=6"
}

finish_test

Added test/reuse5.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
# 2019 February 26
#
# 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.
#
#***********************************************************************
#
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix reuse5
set CLI [test_find_cli]

ifcapable !sharedschema {
  finish_test
  return
}

do_execsql_test 1.0 {
  CREATE TABLE t1(x, y);
  CREATE TABLE t2(a, b, c);
  CREATE INDEX t1x ON t1(x);
  CREATE INDEX t1y ON t1(y);
  CREATE VIEW v1 AS SELECT * FROM t2;
}

foreach {tn sql out1 out2} {
  1 {
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(a, b, c);
    CREATE INDEX t1x ON t1(x);
    CREATE INDEX t1y ON t1(y);
    CREATE VIEW v1 AS SELECT * FROM t2;
  } {
    test.db2 is compatible
  } {}

  2 {
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(a, b, c);
    CREATE INDEX t1x ON t1(x);
    CREATE INDEX t1y ON t1(y);
    CREATE VIEW v1 AS SELECT * FROM t2;
    CREATE TABLE x1(x);
    DROP TABLE x1;
  } {
    test.db2 is NOT compatible (schema cookie)
  } {
    Fixing test.db2... test.db2 is compatible
  }

  3 {
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(a, b, c);
    CREATE INDEX t1y ON t1(y);
    CREATE VIEW v1 AS SELECT * FROM t2;
  } {
    test.db2 is NOT compatible (objects)
  } {}

  4 {
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(a, b, c);
    CREATE INDEX t1x ON t1(X);
    CREATE INDEX t1y ON t1(y);
    CREATE VIEW v1 AS SELECT * FROM t2;
  } {
    test.db2 is NOT compatible (SQL)
  } {}

  5 {
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(a, b, c);
    CREATE INDEX t1y ON t1(y);
    CREATE INDEX t1x ON t1(x);
    CREATE VIEW v1 AS SELECT * FROM t2;
  } {
    test.db2 is NOT compatible (root pages)
  } {
    Fixing test.db2... test.db2 is compatible
  }

  6 {
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(a, b, c);
    CREATE INDEX t1x ON t1(x);
    CREATE INDEX t1y ON t1(y);
    CREATE VIEW v1 AS SELECT * FROM t2;
    DROP INDEX t1x;
    CREATE INDEX t1x ON t1(x);
  } {
    test.db2 is NOT compatible (order of sqlite_master rows)
  } {
    Fixing test.db2... test.db2 is compatible
  }

} {
  forcedelete test.db2
  sqlite3 db2 test.db2
  db2 eval $sql
  db2 close

  if {$out2==""} {set out2 $out1}

  do_test 1.$tn.1 {
    catchcmd test.db ".shared-schema check test.db2"
  } [list 0 [string trim $out1]]

  do_test 1.$tn.2 {
    catchcmd test.db ".shared-schema fix test.db2"
  } [list 0 [string trim $out2]]

  do_test 1.$tn.3 {
    catchcmd test.db2 "PRAGMA integrity_check"
  } [list 0 ok]
}


finish_test

Added test/reuse6.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
143
# 2019 February 26
#
# 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.
#
#***********************************************************************
#
#

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

ifcapable !sharedschema {
  finish_test
  return
}

do_execsql_test 1.0 {
  CREATE TABLE t1(x, y);
  CREATE TABLE t2(a, b, c);
  CREATE INDEX t1x ON t1(x);
  CREATE INDEX t1y ON t1(y);
  CREATE VIEW v1 AS SELECT * FROM t2;

  INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6);
  INSERT INTO t2 VALUES('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i');

  ATTACH 'test.db2' AS aux;
  CREATE TABLE t3(i, ii);
  INSERT INTO t3 VALUES(10, 20);
}

sqlite3 db1 test.db -shared-schema 1
sqlite3 db2 test.db -shared-schema 1

do_execsql_test -db db1 1.1 {
  ATTACH 'test.db2' AS aux;
}

do_test 1.2 {
  execsql {SELECT * FROM t3} db1
} {10 20}

do_execsql_test -db db2 1.3 {
  ATTACH 'test.db2' AS aux;
}

do_test 1.3 {
  execsql {SELECT * FROM t3} db1
} {10 20}

do_execsql_test -db db2 1.5 {
  SELECT * FROM t3;
} {10 20}

do_test 1.6 {
  execsql {SELECT * FROM t3} db1
} {10 20}

db1 close
db2 close

#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
forcedelete test.db3
do_execsql_test 2.0 {
  CREATE TABLE t1(x, y);
  ATTACH 'test.db2' AS aux2;
  CREATE TABLE aux2.t2(x, y);
  ATTACH 'test.db3' AS aux3;
  CREATE TABLE aux3.t3(x, y);
}

sqlite3 db1 test.db -shared-schema 1
do_execsql_test -db db1 2.1 {
  ATTACH 'test.db2' AS aux2;
  ATTACH 'test.db3' AS aux3;
}

do_test 2.2.1 {
  catchsql { SELECT * FROM aux2.nosuchtable } db1
} {1 {no such table: aux2.nosuchtable}}
do_test 2.2.2 {
  sqlite3_errcode db1
} {SQLITE_ERROR}
db1 close

#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
ifcapable fts5 {
  do_execsql_test 3.0 {
    CREATE VIRTUAL TABLE ft USING fts5(a, b);
    ATTACH 'test.db2' AS aux;
    CREATE TABLE aux.t1(x, y, z);
  }

  sqlite3 db1 test.db -shared-schema 1
  do_execsql_test -db db1 3.1 {
    ATTACH 'test.db2' AS aux;
  }

  do_execsql_test -db db1 3.2 {
    SELECT * FROM main.ft, aux.t1;
  }
  db1 close
}

#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
ifcapable fts5 {
  do_execsql_test 4.0 {
    CREATE VIRTUAL TABLE ft USING fts5(a, b);
  }
  forcecopy test.db test.db2

  sqlite3 db1 test.db -shared-schema 1
  do_execsql_test -db db1 4.1 {
    ATTACH 'test.db2' AS aux;
    SELECT * FROM main.ft;
    SELECT * FROM aux.ft;
  }

  do_execsql_test -db db1 4.2 {
    SELECT * FROM main.ft, aux.ft
  }
}







finish_test

Added test/reusefault.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
# 2019 February 12
#
# 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.
#
#***********************************************************************
#
#

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

ifcapable !sharedschema {
  finish_test
  return
}

do_execsql_test 1.0 {
  PRAGMA cache_size = 10;
  CREATE TABLE t1(a UNIQUE, b UNIQUE);
  INSERT INTO t1 VALUES(1, 2), (3, 4);
}
faultsim_save_and_close

do_faultsim_test 1.1 -prep {
  faultsim_restore
  sqlite3 db test.db -shared-schema 1
} -body {
  execsql { SELECT * FROM t1 }
} -test {
  faultsim_test_result {0 {1 2 3 4}}
}

do_faultsim_test 1.2 -prep {
  faultsim_restore
  sqlite3 db test.db -shared-schema 1
  execsql { SELECT * FROM t1 }
  sqlite3 db2 test.db
  db2 eval {CREATE TABLE a(a)}
  db2 close
} -body {
  execsql { SELECT  * FROM t1 }
} -test {
  faultsim_test_result {0 {1 2 3 4}}
}


finish_test

Changes to test/tclsqlite.test.

22
23
24
25
26
27
28



29
30
31
32
33
34
35
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tcl

# Check the error messages generated by tclsqlite
#
set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nofollow BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"



if {[sqlite3 -has-codec]} {
  append r " ?-key CODECKEY?"
}
do_test tcl-1.1 {
  set v [catch {sqlite3 -bogus} msg]
  regsub {really_sqlite3} $msg {sqlite3} msg
  lappend v $msg







>
>
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tcl

# Check the error messages generated by tclsqlite
#
set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nofollow BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
ifcapable sharedschema {
  append r " ?-shared-schema BOOLEAN?"
}
if {[sqlite3 -has-codec]} {
  append r " ?-key CODECKEY?"
}
do_test tcl-1.1 {
  set v [catch {sqlite3 -bogus} msg]
  regsub {really_sqlite3} $msg {sqlite3} msg
  lappend v $msg

Changes to test/threadtest3.c.

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
...
516
517
518
519
520
521
522
523

524
525
526

527

528
529
530
531
532
533
534
...
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
...
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
....
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
....
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
....
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
....
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
....
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
....
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
....
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
....
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
....
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
....
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
....
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
....
1429
1430
1431
1432
1433
1434
1435

1436
1437
1438
1439
1440
1441
1442
....
1453
1454
1455
1456
1457
1458
1459

1460
1461
1462
1463
1464
1465
1466

/* 
** The "Set Error Line" macro.
*/
#define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__))

/* Database functions */
#define opendb(w,x,y,z)         (SEL(w), opendb_x(w,x,y,z))
#define closedb(y,z)            (SEL(y), closedb_x(y,z))

/* Functions to execute SQL */
#define sql_script(x,y,z)       (SEL(x), sql_script_x(x,y,z))
#define integrity_check(x,y)    (SEL(x), integrity_check_x(x,y))
#define execsql_i64(x,y,...)    (SEL(x), execsql_i64_x(x,y,__VA_ARGS__))
#define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__))
................................................................................
  return 1;
}

static void opendb_x(
  Error *pErr,                    /* IN/OUT: Error code */
  Sqlite *pDb,                    /* OUT: Database handle */
  const char *zFile,              /* Database file name */
  int bDelete                     /* True to delete db file before opening */

){
  if( pErr->rc==SQLITE_OK ){
    int rc;

    int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI;

    if( bDelete ) unlink(zFile);
    rc = sqlite3_open_v2(zFile, &pDb->db, flags, 0);
    if( rc ){
      sqlite_error(pErr, pDb, "open");
      sqlite3_close(pDb->db);
      pDb->db = 0;
    }else{
................................................................................
#define WALTHREAD3_NTHREAD  6

static char *walthread1_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int nIter = 0;                  /* Iterations so far */

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    const char *azSql[] = {
      "SELECT md5sum(x) FROM t1 WHERE rowid != (SELECT max(rowid) FROM t1)",
      "SELECT x FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)",
    };
    char *z1, *z2, *z3;

................................................................................
}

static char *walthread1_ckpt_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int nCkpt = 0;                  /* Checkpoints so far */

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    usleep(500*1000);
    execsql(&err, &db, "PRAGMA wal_checkpoint");
    if( err.rc==SQLITE_OK ) nCkpt++;
    clear_error(&err, SQLITE_BUSY);
  }
  closedb(&err, &db);
................................................................................

static void walthread1(int nMs){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  Threadset threads = {0};        /* Test threads */
  int i;                          /* Iterator variable */

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db,
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x PRIMARY KEY);"
      "INSERT INTO t1 VALUES(randomblob(100));"
      "INSERT INTO t1 VALUES(randomblob(100));"
      "INSERT INTO t1 SELECT md5sum(x) FROM t1;"
  );
................................................................................
  const char *zJournal = "PRAGMA journal_mode = WAL";
  if( iArg ){ zJournal = "PRAGMA journal_mode = DELETE"; }

  while( !timetostop(&err) ){
    int journal_exists = 0;
    int wal_exists = 0;

    opendb(&err, &db, "test.db", 0);

    sql_script(&err, &db, zJournal);
    clear_error(&err, SQLITE_BUSY);
    sql_script(&err, &db, "BEGIN");
    sql_script(&err, &db, "INSERT INTO t1 VALUES(NULL, randomblob(100))");

    journal_exists = (filesize(&err, "test.db-journal") >= 0);
................................................................................
}

static void walthread2(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, "CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE)");
  closedb(&err, &db);

  setstoptime(&err, nMs);
  launch_thread(&err, &threads, walthread2_thread, 0);
  launch_thread(&err, &threads, walthread2_thread, 0);
  launch_thread(&err, &threads, walthread2_thread, (void*)1);
................................................................................

static char *walthread3_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 iNextWrite;                 /* Next value this thread will write */
  int iArg = PTR2INT(pArg);

  opendb(&err, &db, "test.db", 0);
  sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10");

  iNextWrite = iArg+1;
  while( 1 ){
    i64 sum1;
    i64 sum2;
    int stop = 0;                 /* True to stop executing (test timed out) */
................................................................................

static void walthread3(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};
  int i;

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);"
      "CREATE INDEX i1 ON t1(sum1);"
      "CREATE INDEX i2 ON t1(sum2);"
      "INSERT INTO t1 VALUES(0, 0, 0);"
  );
................................................................................
  print_and_free_err(&err);
}

static char *walthread4_reader_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    integrity_check(&err, &db);
  }
  closedb(&err, &db);

  print_and_free_err(&err);
  return 0;
................................................................................
}

static char *walthread4_writer_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 iRow = 1;

  opendb(&err, &db, "test.db", 0);
  sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 15;");
  while( !timetostop(&err) ){
    execsql_i64(
        &err, &db, "REPLACE INTO t1 VALUES(:iRow, randomblob(300))", &iRow
    );
    iRow++;
    if( iRow==10 ) iRow = 0;
................................................................................
}

static void walthread4(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);"
  );
  closedb(&err, &db);

  setstoptime(&err, nMs);
................................................................................
}

static char *walthread5_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 nRow;

  opendb(&err, &db, "test.db", 0);
  nRow = execsql_i64(&err, &db, "SELECT count(*) FROM t1");
  closedb(&err, &db);

  if( nRow!=65536 ) test_error(&err, "Bad row count: %d", (int)nRow);
  print_and_free_err(&err);
  return 0;
}
static void walthread5(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
      "PRAGMA wal_autocheckpoint = 0;"
      "PRAGMA page_size = 1024;"
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x);"
      "BEGIN;"
      "INSERT INTO t1 VALUES(randomblob(900));"
................................................................................
  sql_script(pErr, pDb, "COMMIT");
}
static void cgt_pager_1(int nMs){
  void (*xSub)(Error *, Sqlite *);
  Error err = {0};
  Sqlite db = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db,
      "PRAGMA cache_size = 2000;"
      "PRAGMA page_size = 1024;"
      "CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);"
  );

  xSub = cgt_pager_1_populate; xSub(&err, &db);
................................................................................

static char *dynamic_triggers_1(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int nDrop = 0;
  int nCreate = 0;

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    int i;

    for(i=1; i<9; i++){
      char *zSql = sqlite3_mprintf(
        "CREATE TRIGGER itr%d BEFORE INSERT ON t%d BEGIN "
          "INSERT INTO t%d VALUES(new.x, new.y);"
................................................................................
static char *dynamic_triggers_2(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 iVal = 0;
  int nInsert = 0;
  int nDelete = 0;

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    do {
      iVal = (iVal+1)%100;
      execsql(&err, &db, "INSERT INTO t1 VALUES(:iX, :iY+1)", &iVal, &iVal);
      nInsert++;
    } while( iVal );

................................................................................
}

static void dynamic_triggers(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
      "PRAGMA page_size = 1024;"
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x, y);"
      "CREATE TABLE t2(x, y);"
      "CREATE TABLE t3(x, y);"
      "CREATE TABLE t4(x, y);"
................................................................................


#include "tt3_checkpoint.c"
#include "tt3_index.c"
#include "tt3_lookaside1.c"
#include "tt3_vacuum.c"
#include "tt3_stress.c"


int main(int argc, char **argv){
  struct ThreadTest {
    void (*xTest)(int);   /* Routine for running this test */
    const char *zTest;    /* Name of this test */
    int nMs;              /* How long to run this test, in milliseconds */
  } aTest[] = {
................................................................................
    { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 },

    { create_drop_index_1, "create_drop_index_1", 10000 },
    { lookaside1,          "lookaside1", 10000 },
    { vacuum1,             "vacuum1", 10000 },
    { stress1,             "stress1", 10000 },
    { stress2,             "stress2", 60000 },

  };
  static char *substArgv[] = { 0, "*", 0 };
  int i, iArg;
  int nTestfound = 0;

  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
  if( argc<2 ){







|







 







|
>



>
|
>







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|












|







 







|







 







|







 







|







 







|







 







>







 







>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
...
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
...
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
....
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
....
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
....
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
....
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
....
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
....
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
....
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
....
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
....
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
....
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
....
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
....
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
....
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471

/* 
** The "Set Error Line" macro.
*/
#define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__))

/* Database functions */
#define opendb(w,x,y,z,f)       (SEL(w), opendb_x(w,x,y,z,f))
#define closedb(y,z)            (SEL(y), closedb_x(y,z))

/* Functions to execute SQL */
#define sql_script(x,y,z)       (SEL(x), sql_script_x(x,y,z))
#define integrity_check(x,y)    (SEL(x), integrity_check_x(x,y))
#define execsql_i64(x,y,...)    (SEL(x), execsql_i64_x(x,y,__VA_ARGS__))
#define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__))
................................................................................
  return 1;
}

static void opendb_x(
  Error *pErr,                    /* IN/OUT: Error code */
  Sqlite *pDb,                    /* OUT: Database handle */
  const char *zFile,              /* Database file name */
  int bDelete,                    /* True to delete db file before opening */
  int flags
){
  if( pErr->rc==SQLITE_OK ){
    int rc;
    if( flags==0 ){
      flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI;
    }
    if( bDelete ) unlink(zFile);
    rc = sqlite3_open_v2(zFile, &pDb->db, flags, 0);
    if( rc ){
      sqlite_error(pErr, pDb, "open");
      sqlite3_close(pDb->db);
      pDb->db = 0;
    }else{
................................................................................
#define WALTHREAD3_NTHREAD  6

static char *walthread1_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int nIter = 0;                  /* Iterations so far */

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    const char *azSql[] = {
      "SELECT md5sum(x) FROM t1 WHERE rowid != (SELECT max(rowid) FROM t1)",
      "SELECT x FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)",
    };
    char *z1, *z2, *z3;

................................................................................
}

static char *walthread1_ckpt_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int nCkpt = 0;                  /* Checkpoints so far */

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    usleep(500*1000);
    execsql(&err, &db, "PRAGMA wal_checkpoint");
    if( err.rc==SQLITE_OK ) nCkpt++;
    clear_error(&err, SQLITE_BUSY);
  }
  closedb(&err, &db);
................................................................................

static void walthread1(int nMs){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  Threadset threads = {0};        /* Test threads */
  int i;                          /* Iterator variable */

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db,
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x PRIMARY KEY);"
      "INSERT INTO t1 VALUES(randomblob(100));"
      "INSERT INTO t1 VALUES(randomblob(100));"
      "INSERT INTO t1 SELECT md5sum(x) FROM t1;"
  );
................................................................................
  const char *zJournal = "PRAGMA journal_mode = WAL";
  if( iArg ){ zJournal = "PRAGMA journal_mode = DELETE"; }

  while( !timetostop(&err) ){
    int journal_exists = 0;
    int wal_exists = 0;

    opendb(&err, &db, "test.db", 0, 0);

    sql_script(&err, &db, zJournal);
    clear_error(&err, SQLITE_BUSY);
    sql_script(&err, &db, "BEGIN");
    sql_script(&err, &db, "INSERT INTO t1 VALUES(NULL, randomblob(100))");

    journal_exists = (filesize(&err, "test.db-journal") >= 0);
................................................................................
}

static void walthread2(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, "CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE)");
  closedb(&err, &db);

  setstoptime(&err, nMs);
  launch_thread(&err, &threads, walthread2_thread, 0);
  launch_thread(&err, &threads, walthread2_thread, 0);
  launch_thread(&err, &threads, walthread2_thread, (void*)1);
................................................................................

static char *walthread3_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 iNextWrite;                 /* Next value this thread will write */
  int iArg = PTR2INT(pArg);

  opendb(&err, &db, "test.db", 0, 0);
  sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10");

  iNextWrite = iArg+1;
  while( 1 ){
    i64 sum1;
    i64 sum2;
    int stop = 0;                 /* True to stop executing (test timed out) */
................................................................................

static void walthread3(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};
  int i;

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);"
      "CREATE INDEX i1 ON t1(sum1);"
      "CREATE INDEX i2 ON t1(sum2);"
      "INSERT INTO t1 VALUES(0, 0, 0);"
  );
................................................................................
  print_and_free_err(&err);
}

static char *walthread4_reader_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    integrity_check(&err, &db);
  }
  closedb(&err, &db);

  print_and_free_err(&err);
  return 0;
................................................................................
}

static char *walthread4_writer_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 iRow = 1;

  opendb(&err, &db, "test.db", 0, 0);
  sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 15;");
  while( !timetostop(&err) ){
    execsql_i64(
        &err, &db, "REPLACE INTO t1 VALUES(:iRow, randomblob(300))", &iRow
    );
    iRow++;
    if( iRow==10 ) iRow = 0;
................................................................................
}

static void walthread4(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);"
  );
  closedb(&err, &db);

  setstoptime(&err, nMs);
................................................................................
}

static char *walthread5_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 nRow;

  opendb(&err, &db, "test.db", 0, 0);
  nRow = execsql_i64(&err, &db, "SELECT count(*) FROM t1");
  closedb(&err, &db);

  if( nRow!=65536 ) test_error(&err, "Bad row count: %d", (int)nRow);
  print_and_free_err(&err);
  return 0;
}
static void walthread5(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
      "PRAGMA wal_autocheckpoint = 0;"
      "PRAGMA page_size = 1024;"
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x);"
      "BEGIN;"
      "INSERT INTO t1 VALUES(randomblob(900));"
................................................................................
  sql_script(pErr, pDb, "COMMIT");
}
static void cgt_pager_1(int nMs){
  void (*xSub)(Error *, Sqlite *);
  Error err = {0};
  Sqlite db = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db,
      "PRAGMA cache_size = 2000;"
      "PRAGMA page_size = 1024;"
      "CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);"
  );

  xSub = cgt_pager_1_populate; xSub(&err, &db);
................................................................................

static char *dynamic_triggers_1(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int nDrop = 0;
  int nCreate = 0;

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    int i;

    for(i=1; i<9; i++){
      char *zSql = sqlite3_mprintf(
        "CREATE TRIGGER itr%d BEFORE INSERT ON t%d BEGIN "
          "INSERT INTO t%d VALUES(new.x, new.y);"
................................................................................
static char *dynamic_triggers_2(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  i64 iVal = 0;
  int nInsert = 0;
  int nDelete = 0;

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    do {
      iVal = (iVal+1)%100;
      execsql(&err, &db, "INSERT INTO t1 VALUES(:iX, :iY+1)", &iVal, &iVal);
      nInsert++;
    } while( iVal );

................................................................................
}

static void dynamic_triggers(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
      "PRAGMA page_size = 1024;"
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x, y);"
      "CREATE TABLE t2(x, y);"
      "CREATE TABLE t3(x, y);"
      "CREATE TABLE t4(x, y);"
................................................................................


#include "tt3_checkpoint.c"
#include "tt3_index.c"
#include "tt3_lookaside1.c"
#include "tt3_vacuum.c"
#include "tt3_stress.c"
#include "tt3_reuseschema.c"

int main(int argc, char **argv){
  struct ThreadTest {
    void (*xTest)(int);   /* Routine for running this test */
    const char *zTest;    /* Name of this test */
    int nMs;              /* How long to run this test, in milliseconds */
  } aTest[] = {
................................................................................
    { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 },

    { create_drop_index_1, "create_drop_index_1", 10000 },
    { lookaside1,          "lookaside1", 10000 },
    { vacuum1,             "vacuum1", 10000 },
    { stress1,             "stress1", 10000 },
    { stress2,             "stress2", 60000 },
    { reuse_schema_1,      "reuse_schema_1", 20000 },
  };
  static char *substArgv[] = { 0, "*", 0 };
  int i, iArg;
  int nTestfound = 0;

  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
  if( argc<2 ){

Changes to test/tt3_checkpoint.c.

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  return SQLITE_OK;
}

static char *checkpoint_starvation_reader(int iTid, void *pArg){
  Error err = {0};
  Sqlite db = {0};

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    i64 iCount1, iCount2;
    sql_script(&err, &db, "BEGIN");
    iCount1 = execsql_i64(&err, &db, "SELECT count(x) FROM t1");
    usleep(CHECKPOINT_STARVATION_READMS*1000);
    iCount2 = execsql_i64(&err, &db, "SELECT count(x) FROM t1");
    sql_script(&err, &db, "COMMIT");
................................................................................
static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};
  int nInsert = 0;
  int i;

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
      "PRAGMA page_size = 1024;"
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x);"
  );

  setstoptime(&err, nMs);







|







 







|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  return SQLITE_OK;
}

static char *checkpoint_starvation_reader(int iTid, void *pArg){
  Error err = {0};
  Sqlite db = {0};

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    i64 iCount1, iCount2;
    sql_script(&err, &db, "BEGIN");
    iCount1 = execsql_i64(&err, &db, "SELECT count(x) FROM t1");
    usleep(CHECKPOINT_STARVATION_READMS*1000);
    iCount2 = execsql_i64(&err, &db, "SELECT count(x) FROM t1");
    sql_script(&err, &db, "COMMIT");
................................................................................
static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};
  int nInsert = 0;
  int i;

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
      "PRAGMA page_size = 1024;"
      "PRAGMA journal_mode = WAL;"
      "CREATE TABLE t1(x);"
  );

  setstoptime(&err, nMs);

Changes to test/tt3_index.c.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


static char *create_drop_index_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  while( !timetostop(&err) ){
    opendb(&err, &db, "test.db", 0);

    sql_script(&err, &db, 
      "DROP INDEX IF EXISTS i1;"
      "DROP INDEX IF EXISTS i2;"
      "DROP INDEX IF EXISTS i3;"
      "DROP INDEX IF EXISTS i4;"

................................................................................
}

static void create_drop_index_1(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
     "CREATE TABLE t11(a, b, c, d);"
     "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) "
     "INSERT INTO t11 SELECT x,x,x,x FROM data;"
  );
  closedb(&err, &db);








|







 







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


static char *create_drop_index_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  while( !timetostop(&err) ){
    opendb(&err, &db, "test.db", 0, 0);

    sql_script(&err, &db, 
      "DROP INDEX IF EXISTS i1;"
      "DROP INDEX IF EXISTS i2;"
      "DROP INDEX IF EXISTS i3;"
      "DROP INDEX IF EXISTS i4;"

................................................................................
}

static void create_drop_index_1(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
     "CREATE TABLE t11(a, b, c, d);"
     "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) "
     "INSERT INTO t11 SELECT x,x,x,x FROM data;"
  );
  closedb(&err, &db);

Changes to test/tt3_lookaside1.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
** that is suspected to exist at time of writing.
*/

static char *lookaside1_thread_reader(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0);

  while( !timetostop(&err) ){
    sqlite3_stmt *pStmt = 0;
    int rc;

    sqlite3_prepare_v2(db.db, "SELECT 1 FROM t1", -1, &pStmt, 0);
    while( sqlite3_step(pStmt)==SQLITE_ROW ){
................................................................................
  return sqlite3_mprintf("ok");
}

static char *lookaside1_thread_writer(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0);

  do{
    sql_script(&err, &db, 
      "BEGIN;"
        "UPDATE t3 SET i=i+1 WHERE x=1;"
      "ROLLBACK;"
    );
................................................................................


static void lookaside1(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
     "CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;"
     "WITH data(x,y) AS ("
     "  SELECT 1, quote(randomblob(750)) UNION ALL "
     "  SELECT x*2, y||y FROM data WHERE x<5) "
     "INSERT INTO t1 SELECT y FROM data;"








|







 







|







 







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
** that is suspected to exist at time of writing.
*/

static char *lookaside1_thread_reader(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0, 0);

  while( !timetostop(&err) ){
    sqlite3_stmt *pStmt = 0;
    int rc;

    sqlite3_prepare_v2(db.db, "SELECT 1 FROM t1", -1, &pStmt, 0);
    while( sqlite3_step(pStmt)==SQLITE_ROW ){
................................................................................
  return sqlite3_mprintf("ok");
}

static char *lookaside1_thread_writer(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0, 0);

  do{
    sql_script(&err, &db, 
      "BEGIN;"
        "UPDATE t3 SET i=i+1 WHERE x=1;"
      "ROLLBACK;"
    );
................................................................................


static void lookaside1(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
     "CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;"
     "WITH data(x,y) AS ("
     "  SELECT 1, quote(randomblob(750)) UNION ALL "
     "  SELECT x*2, y||y FROM data WHERE x<5) "
     "INSERT INTO t1 SELECT y FROM data;"

Added test/tt3_reuseschema.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
/*
** 2014 December 9
**
** 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.
**
*************************************************************************
**
**     reuse_schema_1
*/


static char *reuse_schema_thread(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int iRep = 0;

  while( !timetostop(&err) ){
    int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SHARED_SCHEMA;
    opendb(&err, &db, "test.db", 0, f);

    execsql_i64(&err, &db, "SELECT count(*) FROM t1");
    sql_script(&err, &db, "ATTACH 'test.db2' AS aux");
    execsql_i64(&err, &db, "SELECT count(*) FROM t1");

    closedb(&err, &db);
    iRep++;
  }

  print_and_free_err(&err);
  return sqlite3_mprintf("%d", iRep);
}

static void reuse_schema_1(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
     "CREATE TABLE t1(a, b, c, d);"
     "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) "
     "INSERT INTO t1 SELECT x,x,x,x FROM data;"
  );
  closedb(&err, &db);
  opendb(&err, &db, "test.db2", 1, 0);
  sql_script(&err, &db, 
#ifdef SQLITE_ENABLE_FTS5
     "CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, d);"
#else
     "CREATE TABLE t2(a, b, c, d);"
#endif
     "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) "
     "INSERT INTO t2 SELECT x*2,x*2,x*2,x*2 FROM data;"
  );
  closedb(&err, &db);

  setstoptime(&err, nMs);

  launch_thread(&err, &threads, reuse_schema_thread, 0);
  launch_thread(&err, &threads, reuse_schema_thread, 0);
  launch_thread(&err, &threads, reuse_schema_thread, 0);
  launch_thread(&err, &threads, reuse_schema_thread, 0);
  launch_thread(&err, &threads, reuse_schema_thread, 0);

  join_all_threads(&err, &threads);
  sqlite3_enable_shared_cache(0);
  print_and_free_err(&err);
}

Changes to test/tt3_stress.c.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/*
** Thread 1. CREATE and DROP a table.
*/
static char *stress_thread_1(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    sql_script(&err, &db, "CREATE TABLE IF NOT EXISTS t1(a PRIMARY KEY, b)");
    clear_error(&err, SQLITE_LOCKED);
    sql_script(&err, &db, "DROP TABLE IF EXISTS t1");
    clear_error(&err, SQLITE_LOCKED);
  }
  closedb(&err, &db);
................................................................................
/*
** Thread 2. Open and close database connections.
*/
static char *stress_thread_2(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  while( !timetostop(&err) ){
    opendb(&err, &db, "test.db", 0);
    sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
    clear_error(&err, SQLITE_LOCKED);
    closedb(&err, &db);
  }
  print_and_free_err(&err);
  return sqlite3_mprintf("ok");
}
................................................................................
static char *stress_thread_3(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  int i1 = 0;
  int i2 = 0;

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;");
    i1++;
    if( err.rc ) i2++;
    clear_error(&err, SQLITE_LOCKED);
    clear_error(&err, SQLITE_ERROR);
  }
................................................................................
static char *stress_thread_4(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int i1 = 0;
  int i2 = 0;
  int iArg = PTR2INT(pArg);

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    if( iArg ){
      closedb(&err, &db);
      opendb(&err, &db, "test.db", 0);
    }
    sql_script(&err, &db, 
        "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop LIMIT 200) "
        "INSERT INTO t1 VALUES(randomblob(60), randomblob(60));"
    );
    i1++;
    if( err.rc ) i2++;
................................................................................
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int iArg = PTR2INT(pArg);

  int i1 = 0;
  int i2 = 0;

  opendb(&err, &db, "test.db", 0);
  while( !timetostop(&err) ){
    i64 i = (i1 % 4);
    if( iArg ){
      closedb(&err, &db);
      opendb(&err, &db, "test.db", 0);
    }
    execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i);
    i1++;
    if( err.rc ) i2++;
    clear_error(&err, SQLITE_LOCKED);
  }
  closedb(&err, &db);
................................................................................
}

static char *stress2_workload19(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  const char *zDb = (const char*)pArg;
  while( !timetostop(&err) ){
    opendb(&err, &db, zDb, 0);
    sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
    clear_error(&err, SQLITE_LOCKED);
    closedb(&err, &db);
  }
  print_and_free_err(&err);
  return sqlite3_mprintf("ok");
}
................................................................................
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int i1 = 0;
  int i2 = 0;

  while( !timetostop(&err) ){
    int cnt;
    opendb(&err, &db, pCtx->zDb, 0);
    for(cnt=0; err.rc==SQLITE_OK && cnt<STRESS2_TABCNT; cnt++){
      pCtx->xProc(&err, &db, i1);
      i2 += (err.rc==SQLITE_OK);
      clear_error(&err, SQLITE_LOCKED);
      i1++;
    }
    closedb(&err, &db);
................................................................................

  int i;
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  /* To make sure the db file is empty before commencing */
  opendb(&err, &db, zDb, 1);
  sql_script(&err, &db, 
      "CREATE TABLE IF NOT EXISTS t0(x PRIMARY KEY, y, z);"
      "CREATE INDEX IF NOT EXISTS i0 ON t0(y);"
  );
  closedb(&err, &db);

  setstoptime(&err, nMs);







|







 







|







 







|







 







|



|







 







|




|







 







|







 







|







 







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/*
** Thread 1. CREATE and DROP a table.
*/
static char *stress_thread_1(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    sql_script(&err, &db, "CREATE TABLE IF NOT EXISTS t1(a PRIMARY KEY, b)");
    clear_error(&err, SQLITE_LOCKED);
    sql_script(&err, &db, "DROP TABLE IF EXISTS t1");
    clear_error(&err, SQLITE_LOCKED);
  }
  closedb(&err, &db);
................................................................................
/*
** Thread 2. Open and close database connections.
*/
static char *stress_thread_2(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  while( !timetostop(&err) ){
    opendb(&err, &db, "test.db", 0, 0);
    sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
    clear_error(&err, SQLITE_LOCKED);
    closedb(&err, &db);
  }
  print_and_free_err(&err);
  return sqlite3_mprintf("ok");
}
................................................................................
static char *stress_thread_3(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */

  int i1 = 0;
  int i2 = 0;

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;");
    i1++;
    if( err.rc ) i2++;
    clear_error(&err, SQLITE_LOCKED);
    clear_error(&err, SQLITE_ERROR);
  }
................................................................................
static char *stress_thread_4(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int i1 = 0;
  int i2 = 0;
  int iArg = PTR2INT(pArg);

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    if( iArg ){
      closedb(&err, &db);
      opendb(&err, &db, "test.db", 0, 0);
    }
    sql_script(&err, &db, 
        "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop LIMIT 200) "
        "INSERT INTO t1 VALUES(randomblob(60), randomblob(60));"
    );
    i1++;
    if( err.rc ) i2++;
................................................................................
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int iArg = PTR2INT(pArg);

  int i1 = 0;
  int i2 = 0;

  opendb(&err, &db, "test.db", 0, 0);
  while( !timetostop(&err) ){
    i64 i = (i1 % 4);
    if( iArg ){
      closedb(&err, &db);
      opendb(&err, &db, "test.db", 0, 0);
    }
    execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i);
    i1++;
    if( err.rc ) i2++;
    clear_error(&err, SQLITE_LOCKED);
  }
  closedb(&err, &db);
................................................................................
}

static char *stress2_workload19(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  const char *zDb = (const char*)pArg;
  while( !timetostop(&err) ){
    opendb(&err, &db, zDb, 0, 0);
    sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
    clear_error(&err, SQLITE_LOCKED);
    closedb(&err, &db);
  }
  print_and_free_err(&err);
  return sqlite3_mprintf("ok");
}
................................................................................
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  int i1 = 0;
  int i2 = 0;

  while( !timetostop(&err) ){
    int cnt;
    opendb(&err, &db, pCtx->zDb, 0, 0);
    for(cnt=0; err.rc==SQLITE_OK && cnt<STRESS2_TABCNT; cnt++){
      pCtx->xProc(&err, &db, i1);
      i2 += (err.rc==SQLITE_OK);
      clear_error(&err, SQLITE_LOCKED);
      i1++;
    }
    closedb(&err, &db);
................................................................................

  int i;
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  /* To make sure the db file is empty before commencing */
  opendb(&err, &db, zDb, 1, 0);
  sql_script(&err, &db, 
      "CREATE TABLE IF NOT EXISTS t0(x PRIMARY KEY, y, z);"
      "CREATE INDEX IF NOT EXISTS i0 ON t0(y);"
  );
  closedb(&err, &db);

  setstoptime(&err, nMs);

Changes to test/tt3_vacuum.c.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
..
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
**
*/


static char *vacuum1_thread_writer(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  opendb(&err, &db, "test.db", 0);
  i64 i = 0;

  while( !timetostop(&err) ){
    i++;

    /* Insert lots of rows. Then delete some. */
    execsql(&err, &db, 
................................................................................
  print_and_free_err(&err);
  return sqlite3_mprintf("ok");
}

static char *vacuum1_thread_vacuumer(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  opendb(&err, &db, "test.db", 0);

  do{
    sql_script(&err, &db, "VACUUM");
    clear_error(&err, SQLITE_LOCKED);
  }while( !timetostop(&err) );

  closedb(&err, &db);
................................................................................
}

static void vacuum1(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1);
  sql_script(&err, &db, 
     "CREATE TABLE t1(x PRIMARY KEY, y BLOB);"
     "CREATE INDEX i1 ON t1(y);"
  );
  closedb(&err, &db);

  setstoptime(&err, nMs);







|







 







|







 







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
..
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
**
*/


static char *vacuum1_thread_writer(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  opendb(&err, &db, "test.db", 0, 0);
  i64 i = 0;

  while( !timetostop(&err) ){
    i++;

    /* Insert lots of rows. Then delete some. */
    execsql(&err, &db, 
................................................................................
  print_and_free_err(&err);
  return sqlite3_mprintf("ok");
}

static char *vacuum1_thread_vacuumer(int iTid, void *pArg){
  Error err = {0};                /* Error code and message */
  Sqlite db = {0};                /* SQLite database connection */
  opendb(&err, &db, "test.db", 0, 0);

  do{
    sql_script(&err, &db, "VACUUM");
    clear_error(&err, SQLITE_LOCKED);
  }while( !timetostop(&err) );

  closedb(&err, &db);
................................................................................
}

static void vacuum1(int nMs){
  Error err = {0};
  Sqlite db = {0};
  Threadset threads = {0};

  opendb(&err, &db, "test.db", 1, 0);
  sql_script(&err, &db, 
     "CREATE TABLE t1(x PRIMARY KEY, y BLOB);"
     "CREATE INDEX i1 ON t1(y);"
  );
  closedb(&err, &db);

  setstoptime(&err, nMs);

Changes to tool/mkpragmatab.tcl.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
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
...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
...
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
...
505
506
507
508
509
510
511






512
513
514
515
516
517
518
# the lookup table needed for pragma name lookup in the pragma.c module.
# Then add the extra "case PragTyp_XXXXX:" and subsequent code for the
# new pragma in ../src/pragma.c.
#

# Flag meanings:
set flagMeaning(NeedSchema) {Force schema load before running}
set flagMeaning(ReadOnly)   {Read-only HEADER_VALUE}
set flagMeaning(Result0)    {Acts as query when no argument}
set flagMeaning(Result1)    {Acts as query when has one argument}
set flagMeaning(SchemaReq)  {Schema required - "main" is default}
set flagMeaning(SchemaOpt)  {Schema restricts name search if present}
set flagMeaning(NoColumns)  {OP_ResultRow called with zero columns}
set flagMeaning(NoColumns1) {zero columns if RHS argument is present}

................................................................................
  IF:   !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)

  NAME: cell_size_check
  TYPE: FLAG
  ARG:  SQLITE_CellSizeCk

  NAME: default_cache_size
  FLAG: NeedSchema Result0 SchemaReq NoColumns1
  COLS: cache_size
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)

  NAME: page_size
  FLAG: Result0 SchemaReq NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: secure_delete
  FLAG: Result0
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: page_count
  FLAG: NeedSchema Result0 SchemaReq
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: max_page_count
  TYPE: PAGE_COUNT
  FLAG: NeedSchema Result0 SchemaReq
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: locking_mode
  FLAG: Result0 SchemaReq
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: journal_mode
  FLAG: NeedSchema Result0 SchemaReq
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: journal_size_limit
  FLAG: Result0 SchemaReq
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: cache_size
  FLAG: NeedSchema Result0 SchemaReq NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: mmap_size
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: auto_vacuum
  FLAG: NeedSchema Result0 SchemaReq NoColumns1
  IF:   !defined(SQLITE_OMIT_AUTOVACUUM)

  NAME: incremental_vacuum
  FLAG: NeedSchema NoColumns
  IF:   !defined(SQLITE_OMIT_AUTOVACUUM)

  NAME: temp_store
  FLAG: Result0 NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: temp_store_directory
................................................................................
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN

  NAME: lock_proxy_file
  FLAG: NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE

  NAME: synchronous
  FLAG: NeedSchema Result0 SchemaReq NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: table_info
  FLAG: NeedSchema Result1 SchemaOpt
  ARG:  0
  COLS: cid name type notnull dflt_value pk
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
................................................................................
  TYPE: TABLE_INFO
  FLAG: NeedSchema Result1 SchemaOpt
  ARG:  1
  COLS: cid name type notnull dflt_value pk hidden
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: stats
  FLAG: NeedSchema Result0 SchemaReq
  COLS: tbl idx wdth hght flgs
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)

  NAME: index_info
  TYPE: INDEX_INFO
  ARG:  0
  FLAG: NeedSchema Result1 SchemaOpt
................................................................................

  NAME: index_list
  FLAG: NeedSchema Result1 SchemaOpt
  COLS: seq name unique origin partial
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: database_list
  FLAG: NeedSchema Result0
  COLS: seq name file
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: function_list
  FLAG: Result0
  COLS: name builtin type enc narg flags
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
................................................................................

  NAME: collation_list
  FLAG: Result0
  COLS: seq name
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: foreign_key_list
  FLAG: NeedSchema Result1 SchemaOpt
  COLS: id seq table from to on_update on_delete match
  IF:   !defined(SQLITE_OMIT_FOREIGN_KEY)

  NAME: foreign_key_check
  FLAG: NeedSchema Result0 Result1 SchemaOpt
  COLS: table rowid parent fkid
  IF:   !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
................................................................................
  TYPE: HEADER_VALUE
  ARG:  BTREE_USER_VERSION
  FLAG: NoColumns1 Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: data_version
  TYPE: HEADER_VALUE
  ARG:  BTREE_DATA_VERSION
  FLAG: ReadOnly Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: freelist_count
  TYPE: HEADER_VALUE
  ARG:  BTREE_FREE_PAGE_COUNT
  FLAG: ReadOnly Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: application_id
  TYPE: HEADER_VALUE
  ARG:  BTREE_APPLICATION_ID
  FLAG: NoColumns1 Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: compile_options
  FLAG: Result0
  IF:   !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)

  NAME: wal_checkpoint
  FLAG: NeedSchema
  COLS: busy log checkpointed
  IF:   !defined(SQLITE_OMIT_WAL)

  NAME: wal_autocheckpoint
  IF:   !defined(SQLITE_OMIT_WAL)

  NAME: shrink_memory
................................................................................
puts $fd "\n/* Property flags associated with various pragma. */"
set fv 1
foreach f [lsort [array names allflags]] {
  puts $fd [format {#define PragFlg_%-10s 0x%02x /* %s */} \
             $f $fv $flagMeaning($f)]
  set fv [expr {$fv*2}]
}







# Sort the column lists so that longer column lists occur first
#
proc colscmp {a b} {
  return [expr {[llength $b] - [llength $a]}]
}
set cols_list [lsort -command colscmp $cols_list]







|







 







|












|




|







|







|






|



|







 







|







 







|







 







|







 







|







 







|
|




|
|













|







 







>
>
>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
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
...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
...
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
...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
# the lookup table needed for pragma name lookup in the pragma.c module.
# Then add the extra "case PragTyp_XXXXX:" and subsequent code for the
# new pragma in ../src/pragma.c.
#

# Flag meanings:
set flagMeaning(NeedSchema) {Force schema load before running}
set flagMeaning(OneSchema)  {Only a single schema required}
set flagMeaning(Result0)    {Acts as query when no argument}
set flagMeaning(Result1)    {Acts as query when has one argument}
set flagMeaning(SchemaReq)  {Schema required - "main" is default}
set flagMeaning(SchemaOpt)  {Schema restricts name search if present}
set flagMeaning(NoColumns)  {OP_ResultRow called with zero columns}
set flagMeaning(NoColumns1) {zero columns if RHS argument is present}

................................................................................
  IF:   !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)

  NAME: cell_size_check
  TYPE: FLAG
  ARG:  SQLITE_CellSizeCk

  NAME: default_cache_size
  FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
  COLS: cache_size
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)

  NAME: page_size
  FLAG: Result0 SchemaReq NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: secure_delete
  FLAG: Result0
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: page_count
  FLAG: NeedSchema Result0 SchemaReq OneSchema
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: max_page_count
  TYPE: PAGE_COUNT
  FLAG: NeedSchema Result0 SchemaReq OneSchema
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: locking_mode
  FLAG: Result0 SchemaReq
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: journal_mode
  FLAG: NeedSchema Result0 SchemaReq OneSchema
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: journal_size_limit
  FLAG: Result0 SchemaReq
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: cache_size
  FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: mmap_size
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: auto_vacuum
  FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
  IF:   !defined(SQLITE_OMIT_AUTOVACUUM)

  NAME: incremental_vacuum
  FLAG: NeedSchema NoColumns OneSchema
  IF:   !defined(SQLITE_OMIT_AUTOVACUUM)

  NAME: temp_store
  FLAG: Result0 NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: temp_store_directory
................................................................................
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN

  NAME: lock_proxy_file
  FLAG: NoColumns1
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE

  NAME: synchronous
  FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
  IF:   !defined(SQLITE_OMIT_PAGER_PRAGMAS)

  NAME: table_info
  FLAG: NeedSchema Result1 SchemaOpt
  ARG:  0
  COLS: cid name type notnull dflt_value pk
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
................................................................................
  TYPE: TABLE_INFO
  FLAG: NeedSchema Result1 SchemaOpt
  ARG:  1
  COLS: cid name type notnull dflt_value pk hidden
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: stats
  FLAG: NeedSchema Result0 SchemaReq OneSchema
  COLS: tbl idx wdth hght flgs
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)

  NAME: index_info
  TYPE: INDEX_INFO
  ARG:  0
  FLAG: NeedSchema Result1 SchemaOpt
................................................................................

  NAME: index_list
  FLAG: NeedSchema Result1 SchemaOpt
  COLS: seq name unique origin partial
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: database_list
  FLAG: NeedSchema Result0 OneSchema
  COLS: seq name file
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: function_list
  FLAG: Result0
  COLS: name builtin type enc narg flags
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
................................................................................

  NAME: collation_list
  FLAG: Result0
  COLS: seq name
  IF:   !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)

  NAME: foreign_key_list
  FLAG: NeedSchema Result1 SchemaOpt OneSchema
  COLS: id seq table from to on_update on_delete match
  IF:   !defined(SQLITE_OMIT_FOREIGN_KEY)

  NAME: foreign_key_check
  FLAG: NeedSchema Result0 Result1 SchemaOpt
  COLS: table rowid parent fkid
  IF:   !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
................................................................................
  TYPE: HEADER_VALUE
  ARG:  BTREE_USER_VERSION
  FLAG: NoColumns1 Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: data_version
  TYPE: HEADER_VALUE
  ARG:  BTREE_DATA_VERSION|PRAGMA_HEADER_VALUE_READONLY
  FLAG: Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: freelist_count
  TYPE: HEADER_VALUE
  ARG:  BTREE_FREE_PAGE_COUNT|PRAGMA_HEADER_VALUE_READONLY
  FLAG: Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: application_id
  TYPE: HEADER_VALUE
  ARG:  BTREE_APPLICATION_ID
  FLAG: NoColumns1 Result0
  IF:   !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)

  NAME: compile_options
  FLAG: Result0
  IF:   !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)

  NAME: wal_checkpoint
  FLAG: NeedSchema OneSchema
  COLS: busy log checkpointed
  IF:   !defined(SQLITE_OMIT_WAL)

  NAME: wal_autocheckpoint
  IF:   !defined(SQLITE_OMIT_WAL)

  NAME: shrink_memory
................................................................................
puts $fd "\n/* Property flags associated with various pragma. */"
set fv 1
foreach f [lsort [array names allflags]] {
  puts $fd [format {#define PragFlg_%-10s 0x%02x /* %s */} \
             $f $fv $flagMeaning($f)]
  set fv [expr {$fv*2}]
}

puts $fd "\n/* For PragTyp_HEADER_VALUE pragmas the Pragma.iArg value is set"
puts $fd "** to the index of the header field to access (always 10 or less)."
puts $fd "** Ored with HEADER_VALUE_READONLY if the field is read only. */"
puts $fd "#define PRAGMA_HEADER_VALUE_READONLY 0x0100"
puts $fd "#define PRAGMA_HEADER_VALUE_MASK 0x00FF\n"

# Sort the column lists so that longer column lists occur first
#
proc colscmp {a b} {
  return [expr {[llength $b] - [llength $a]}]
}
set cols_list [lsort -command colscmp $cols_list]