Compare commits
123 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1ca5bae51 | |||
| 5fd9dbbfc1 | |||
| cc247a2ead | |||
| c1cace0832 | |||
| 5d5017c80e | |||
| 9274c84f9d | |||
| 56fdafb30b | |||
| a153e56893 | |||
| 68610cfae1 | |||
| 356f24f0d3 | |||
| 8bec96953b | |||
| ac18487e2a | |||
| ea602ac6b0 | |||
| 378c763eb3 | |||
| 5b878c61d3 | |||
| 199077fb70 | |||
| dafde4b7de | |||
| 0313979b6b | |||
| 1703ac81c7 | |||
| 6857efa5a8 | |||
| 63bb13dc5a | |||
| 3c1d7e4b84 | |||
| 4d55331f24 | |||
| 082f003903 | |||
| 017616e441 | |||
| 89f4e8c325 | |||
| 8af662c8d6 | |||
| ce3cc96805 | |||
| 7dd6817e58 | |||
| 2f35820fdc | |||
| 85aaf75855 | |||
| 36b4ffef75 | |||
| bd89471096 | |||
| 5422f18381 | |||
| 934eb637c2 | |||
| 8280fcc66f | |||
| 5a5f8b366b | |||
| 73d2d7938e | |||
| e805679133 | |||
| bb85a9053e | |||
| 19b2d07824 | |||
| 02d30805c8 | |||
| 6d78967393 | |||
| 006f49bc9b | |||
| 0a6e45f4d9 | |||
| 8e8c7ccc9b | |||
| c3c71c1451 | |||
| 5e87610fdf | |||
| d3698b7fe8 | |||
| 72d2de6eef | |||
| 0df48684bd | |||
| 106ab91fc8 | |||
| 806e04ab8f | |||
| eb888e2497 | |||
| d973196e30 | |||
| f6b6f46538 | |||
| f8f62070f8 | |||
| 73debcccd1 | |||
| 1430806e39 | |||
| 49c7657ac9 | |||
| e046ccb5f0 | |||
| 0b5d397cb4 | |||
| 2833522a9a | |||
| 06526fef2e | |||
| 7e0410951f | |||
| abbad7ef3c | |||
| cdfb4a29f4 | |||
| ce86700aa7 | |||
| 5593a4c26d | |||
| 88e7099875 | |||
| 28c156d6d6 | |||
| e2e8e9b16f | |||
| ff0e1d8d04 | |||
| 98c5bff6c8 | |||
| 3eadd64c0e | |||
| d32261e7a9 | |||
| 6847647dc4 | |||
| ae070eff74 | |||
| f4c01da150 | |||
| 0d46c528dd | |||
| 209f79234b | |||
| 22b16ac3d0 | |||
| 88a96c49f2 | |||
| 85a76ddc12 | |||
| 20a434abd3 | |||
| 9c2b284dbd | |||
| 74e020a164 | |||
| 94dba01337 | |||
| 239f69e204 | |||
| 05a094d4c5 | |||
| aec53fa5ba | |||
| a011145aae | |||
| 13af9ba7af | |||
| 6170a98cfa | |||
| d0932d5358 | |||
| 61155cb70b | |||
| d746d250f0 | |||
| 155a112b81 | |||
| a5150d4f05 | |||
| 64104062a7 | |||
| 1395c92f1f | |||
| 33a37f5ef0 | |||
| 9d65677e57 | |||
| 6758315c8e | |||
| 5944230305 | |||
| a72a438cd7 | |||
| d62150108a | |||
| 2ce6757bd4 | |||
| 33d1394e1a | |||
| 81fb4ef019 | |||
| d4e11dd78f | |||
| 5add6f25e2 | |||
| 30fdc47579 | |||
| 73e6f3adbd | |||
| 73b8e1f2d6 | |||
| 01d6eab9a5 | |||
| e54087db7b | |||
| d000f2286d | |||
| 8874678ecd | |||
| 8612853f70 | |||
| 62012c0b34 | |||
| 7d3159668c | |||
| d6af93a92c |
@@ -418,6 +418,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -477,6 +478,7 @@ TESTSRC2 = \
|
||||
$(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 \
|
||||
|
||||
@@ -1538,6 +1538,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.35.3.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.35.5.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -726,8 +726,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.35.3'
|
||||
PACKAGE_STRING='sqlite 3.35.3'
|
||||
PACKAGE_VERSION='3.35.5'
|
||||
PACKAGE_STRING='sqlite 3.35.5'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1467,7 +1467,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.35.3 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.35.5 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1532,7 +1532,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.35.3:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.35.5:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1660,7 +1660,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.35.3
|
||||
sqlite configure 3.35.5
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2079,7 +2079,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.35.3, which was
|
||||
It was created by sqlite $as_me 3.35.5, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -12378,7 +12378,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.35.3, which was
|
||||
This file was extended by sqlite $as_me 3.35.5, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12444,7 +12444,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.35.3
|
||||
sqlite config.status 3.35.5
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -0,0 +1,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 <database-1> 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 <reason> indicates the cause of the incompatibility. <reason>
|
||||
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_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_master tables are different.
|
||||
|
||||
<li> <b>schema cookie</b> - the database schemas are compatible, but the
|
||||
schema cookie values ("PRAGMA schema_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_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_prepare\*(),
|
||||
sqlite3_blob_open() or sqlite3_blob_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_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_OPEN_SHARED_SCHEMA connections to modify database
|
||||
schemas, should that be required.
|
||||
|
||||
SQLITE_OPEN_SHARED_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.
|
||||
@@ -579,6 +579,18 @@ static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
}else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){
|
||||
p->inCkpt = op==SQLITE_FCNTL_CKPT_START;
|
||||
if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt;
|
||||
}else if( op==SQLITE_FCNTL_CKSM_FILE ){
|
||||
/* This VFS needs to obtain a pointer to the corresponding database
|
||||
** file handle from within xOpen() calls to open wal files. To do this,
|
||||
** it uses the sqlite3_database_file_object() API to obtain a pointer
|
||||
** to the file-handle used by SQLite to access the db file. This is
|
||||
** fine if cksmvfs happens to be the top-level VFS, but not if there
|
||||
** are one or more wrapper VFS. To handle this case, this file-control
|
||||
** is used to extract the cksmvfs file-handle from any wrapper file
|
||||
** handle. */
|
||||
sqlite3_file **ppFile = (sqlite3_file**)pArg;
|
||||
*ppFile = (sqlite3_file*)p;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = pFile->pMethods->xFileControl(pFile, op, pArg);
|
||||
if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
|
||||
@@ -688,6 +700,8 @@ static int cksmOpen(
|
||||
if( rc ) goto cksm_open_done;
|
||||
if( flags & SQLITE_OPEN_WAL ){
|
||||
sqlite3_file *pDb = sqlite3_database_file_object(zName);
|
||||
rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb);
|
||||
assert( rc==SQLITE_OK );
|
||||
p->pPartner = (CksmFile*)pDb;
|
||||
assert( p->pPartner->pPartner==0 );
|
||||
p->pPartner->pPartner = p;
|
||||
|
||||
@@ -132,6 +132,11 @@ foreach {tn3 create_vfs destroy_vfs} {
|
||||
} {
|
||||
sqlite3rbu_destroy_vfs myrbu
|
||||
}
|
||||
3 {
|
||||
sqlite3_register_cksumvfs
|
||||
} {
|
||||
sqlite3_unregister_cksumvfs
|
||||
}
|
||||
} {
|
||||
|
||||
eval $create_vfs
|
||||
|
||||
+9
-21
@@ -1620,7 +1620,9 @@ char *rbuVacuumIndexStart(
|
||||
zSep = "";
|
||||
for(iCol=0; iCol<pIter->nCol; iCol++){
|
||||
const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol);
|
||||
if( zQuoted[0]=='N' ){
|
||||
if( zQuoted==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}else if( zQuoted[0]=='N' ){
|
||||
bFailed = 1;
|
||||
break;
|
||||
}
|
||||
@@ -4992,28 +4994,14 @@ static int rbuVfsOpen(
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
|
||||
if( pDb ){
|
||||
if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
|
||||
/* This call is to open a *-wal file. Intead, open the *-oal. This
|
||||
** code ensures that the string passed to xOpen() is terminated by a
|
||||
** pair of '\0' bytes in case the VFS attempts to extract a URI
|
||||
** parameter from it. */
|
||||
const char *zBase = zName;
|
||||
size_t nCopy;
|
||||
char *zCopy;
|
||||
/* This call is to open a *-wal file. Intead, open the *-oal. */
|
||||
size_t nOpen;
|
||||
if( rbuIsVacuum(pDb->pRbu) ){
|
||||
zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
|
||||
zBase = sqlite3_filename_wal(zBase);
|
||||
}
|
||||
nCopy = strlen(zBase);
|
||||
zCopy = sqlite3_malloc64(nCopy+2);
|
||||
if( zCopy ){
|
||||
memcpy(zCopy, zBase, nCopy);
|
||||
zCopy[nCopy-3] = 'o';
|
||||
zCopy[nCopy] = '\0';
|
||||
zCopy[nCopy+1] = '\0';
|
||||
zOpen = (const char*)(pFd->zDel = zCopy);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
zOpen = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
|
||||
zOpen = sqlite3_filename_wal(zOpen);
|
||||
}
|
||||
nOpen = strlen(zOpen);
|
||||
((char*)zOpen)[nOpen-3] = 'o';
|
||||
pFd->pRbu = pDb->pRbu;
|
||||
}
|
||||
pDb->pWalFd = pFd;
|
||||
|
||||
@@ -343,6 +343,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -397,6 +398,7 @@ TESTSRC2 = \
|
||||
$(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 \
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
C Fix\san\sassert()\sthat\sin\spreupdate-hook\slogic\s(not\snormally\sbuilt)\sthat\ncan\sbe\sfalse\swhen\srunning\sVACUUM\son\sa\scorrupt\sdatabase\sfile\sunder\nPRAGMA\swritable_schema=ON.
|
||||
D 2021-03-21T18:23:48.037
|
||||
C Merge\schanges\sfrom\sbranch-3.35.\sSpecifically,\sfixes\sfor\sa\srunning\sRBU\swith\sa\scksumvfs\sVFS.
|
||||
D 2021-05-11T11:33:44.444
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in fe6cc1db11e02b308f3ab0ec2504344697b9eaaa410fa73f48d16a143462e5d3
|
||||
F Makefile.in b728d9ef199afe285761e560d8810e7ad4621129c3d47515c484e760d57970d1
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc 6b5428cef2af1288e02faeb602dabe68fbf2de7bc8a8e29c7299778ee08cd35c
|
||||
F Makefile.msc 46c3221d59faccf0502eadd8e6dc69b44f65956b56f88caf74908ccc30010679
|
||||
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
|
||||
F VERSION 75575cade3e93b31a84ffcb0d40de856a49bd3e4c1028dff52432bfae9806adb
|
||||
F VERSION 0c32b05000702ccfdfb5fc72e16b0f965ed664d6cb4fec361196fd0d91eb52c9
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
@@ -34,12 +34,13 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
|
||||
F configure 174eed3b99edc1c897fe32638c5b4068d4abfb282dc545ccc3ee92a472f73d7a x
|
||||
F configure 64b2ab5ac52a8657cfdf97a2a1589441d0deaa859e0d2bbad5ff401829f71676 x
|
||||
F configure.ac 4e4b58b32f88c8da9914a2f2c3158f80e69907eccc019fcc7e3ba14ffd91c640
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/lemon.html 1bb72ece6271df0d901d233551dd985f2c6ba30d09382cf2d321ed951ab57491
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/shared_schema.md 759fc374709fccf4e5d2d0cbd05f8fedd38fb022bdd8a6c5b5f492684c7023b9
|
||||
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
|
||||
F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
@@ -291,7 +292,7 @@ F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0e
|
||||
F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
|
||||
F ext/misc/carray.c b75a0f207391038bf1540d3372f482a95c3613511c7c474db51ede1196321c7c
|
||||
F ext/misc/carray.h de74ac70b2338f416723f7d538026e8ec0b7f1d388319f8f140c9a4d7677f02e
|
||||
F ext/misc/cksumvfs.c 8dc4e1b718e374bed3a9b5c0a08da2922438002e33267311697768e06217b983
|
||||
F ext/misc/cksumvfs.c 2c6b07714f3be6c1200671c53aa781a86d2c472c0fcb2fff520375362eb94303
|
||||
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
|
||||
F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9
|
||||
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
|
||||
@@ -340,7 +341,7 @@ F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6
|
||||
F ext/misc/zipfile.c e35e035bc2765b1ccdcb15f9815c2112843fcbc8f36aa071f0e5935df7072228
|
||||
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
|
||||
F ext/rbu/rbu.c b880ca5cb857d6d6f52e72eb7397813058ef48c78c5402cd04ff2b6b5437f622
|
||||
F ext/rbu/rbu1.test 221d9c18a5e600ac9ac6b1810d99d9f99163a7909ba61597876ab6e4d4beb3d6
|
||||
F ext/rbu/rbu1.test c62904bd9526dcdc3496a21199aaf14ae191bbadbf67f076bf16be6b3f2115c2
|
||||
F ext/rbu/rbu10.test 0a201c32202143f23c81c0144503da339786fc20acb7a2fda11601b65659f314
|
||||
F ext/rbu/rbu11.test 5c834cf491086b45e071eabf71f708febc143e86a384a92de69e0b1a4cace144
|
||||
F ext/rbu/rbu12.test 29f8b2118f6c96fac3755bd6d2b55c2db24f878b1f11fbfbe294f3a230a3dcdc
|
||||
@@ -379,7 +380,7 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697
|
||||
F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b
|
||||
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
|
||||
F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10
|
||||
F ext/rbu/sqlite3rbu.c e6531884442b72f9e0ba47036fb5c4641ea817ff659a642b3984c10b8535b0fd
|
||||
F ext/rbu/sqlite3rbu.c badb52388467f58e67ef104c5276d1ac68b316a30f8ccb2f74eac733625ae236
|
||||
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
|
||||
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
|
||||
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
|
||||
@@ -464,7 +465,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk c6afb1c8bcacc4c3e320ab10259879bc927f0747401e184b64e8f4b78f057ab2
|
||||
F main.mk 723543d76167bf302cfc905d0267f6b6a0ab922bf77add04e1099c7766cb056f
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -476,9 +477,9 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 2d631213818b654faaf08755f26e934134c4769757ae9286981401cd6b571081
|
||||
F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c
|
||||
F src/attach.c 9cbe761e464025694df8e6f6ee4d9f41432c3a255ca9443ccbb4130eeb87cf72
|
||||
F src/alter.c 82ed7c15c1ce2a3bebfa33b85865b0ac227f2b2a5944e495a17975904cd3b1d2
|
||||
F src/analyze.c 8b522a57784406d75f544e6d67f3fe7a7196702d3d954b7678bb4b4fe789e5a4
|
||||
F src/attach.c d176b64d15dfcb08ebd7b11d77cac1d5b08d4ec1e8bd9b59e2f0a84557f95ac9
|
||||
F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853
|
||||
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
@@ -486,17 +487,17 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c cfd2a37794532d765e235a2550ad2732924a6d06b07a3bc9f6a71750e3b3cca1
|
||||
F src/btree.h 096cc53baa58be22b02c896d1cf933c38cfc6d65f9253c1367ece8cc88a24de5
|
||||
F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0
|
||||
F src/build.c 066c44421bf7b73c6fa47f6fb0c0fcf1357c10552bcf8f3f94c6ebede581cd01
|
||||
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
|
||||
F src/build.c 3a2960f823d1c1b8a379cbf9024e5fd45391db95caa7fbe9dd0dc2452ce36b2d
|
||||
F src/callback.c d8cdf5d697a31cf54a2b64bce9001fe24f3522a566f44c9fe1eb3a0c7e291c56
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
|
||||
F src/ctime.c 3552554374bfb39a48f8b0064e11cbcd7f2f5af46bc8136f31f7f79ef3851be5
|
||||
F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf
|
||||
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
|
||||
F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
|
||||
F src/delete.c 73f57a9a183532c344a3135cf8f2a5589376e39183e0b5f562d6b61b2af0f4d8
|
||||
F src/expr.c d681f0b48b1e16173ad8e1e8f7323cda120a0c517cb7a3d5b329c4e2c57f18bd
|
||||
F src/expr.c cfab1113f9eba24f1d6d11b710577c9fcc9cc8e29ed60bd7ac7906be7481dda4
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c e9063648396c58778f77583a678342fe4a9bc82436bf23c5f9f444f2df0fdaa4
|
||||
F src/fkey.c 6dcbab4ead1dbfdc19da70a8650e5734a5124765f75fb840100117a7a45980d2
|
||||
F src/func.c 479f6929be027eb0210cbdde9d3529c012facf082d64a6b854a9415940761e5e
|
||||
F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
@@ -506,7 +507,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c e36be69e3810902eaf7e171260c885bc9547b1d41616c868f1cc46e6a0a3b7fd
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067
|
||||
F src/main.c 2a7ece3a67c646e5fe9984ffe0277d6a76f80ce9715bf2faa591d8cb66b9d913
|
||||
F src/main.c 05b648d678f1d4834628b6e76c692f5fa23f4860a0d1205a195944ca73dd2b21
|
||||
F src/malloc.c c1af4ac5a463648cd2953fd4ac679b3ba9022ce5ec794a60806150ad69dfd33a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -535,23 +536,23 @@ F src/parse.y 2107aff88e361bbf8388fdede3fed20fda875f23ba7585ec83b20e3e16a95670
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 388304fd2d91c39591080b5e0f3c62cfba87db20370e7e0554062bfb29740e9f
|
||||
F src/pragma.c eb42cb9bec189cf18cef5d8fcae56e13bb73ef2b019b198fb48740ced81bce95
|
||||
F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
|
||||
F src/prepare.c e21b54489b5c73b06ada15e6fc79b5c6f64b06701924a6ca98944ae59e06256f
|
||||
F src/pragma.c 300dcb000f9ac0ac35c913f5e232234275e5007d25147a6915e4ae06b4afd662
|
||||
F src/pragma.h ce2b135cde481eeb198af0dfc4781d58528ce80b17580a2b747b8fd4bc969e44
|
||||
F src/prepare.c c8797eefce2ae0249ff595c2f3626c4ce88bafe7135e417c4db4db046b0470de
|
||||
F src/printf.c 2b03a80d7c11bb422115dca175a18bf430e9c9dbaa0eee63b758f0c022f8f34f
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c dd47248c2c914feb0d4428c27d782e2723971d32cfa5536f49306d080df4d45a
|
||||
F src/resolve.c fec151c9c33a6fa2e93d10b4e8cd4084a7c773df36fb3ec6788eb89ae493a1a4
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c 734cf12e42f81f2fe461e41214e6552375e55b62a802784a4f0066ac592e7f4a
|
||||
F src/shell.c.in aa28256887d049badaf93aa30ab5c76a2ec88143a674d685c0e739056702e5c3
|
||||
F src/sqlite.h.in 3426a080ea1f222a73e3bd91e7eacbd30570a0117c03d42c6dde606f33e5e318
|
||||
F src/shell.c.in 8f658734fb8b7205c20f6b0bf7d02886887df60000d261f0c0b478511f4b6cd7
|
||||
F src/sqlite.h.in 4cb58c05f4483125c961d39989c63448ff34b9460abb9bf8f07234028b851887
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
|
||||
F src/sqliteInt.h 0f81c7eb3a40dda0b74d0acdc8f3b134346b40be780b1fe5cc24dd294a928d1a
|
||||
F src/sqliteInt.h 5cbcb97dd2a283121c59756904a912ab7f484f1755f101936f287ba3f4a45599
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/status.c d0956e57c71160155f620a3efeb1e5c05a3f8b9a897dd09c5263268e5d237579
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71
|
||||
F src/tclsqlite.c f4dd32d001c2be33371dca87e30117352f02dad59a2e5428c97f08703360a169
|
||||
F src/test1.c cff43d8e21be543b77651b4d2caf49bd6488fee220f8540ecd9f71d13169dbd1
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
@@ -567,7 +568,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
|
||||
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
|
||||
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c 98698f5242be88af75eaac54adde573471d5ed2f6484e0dac034cb1e763a551a
|
||||
F src/test_config.c c7625911811828ba7065c4c789d68a61835f42239d5bd7f4a08aba7c44ccded9
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91
|
||||
F src/test_devsym.c aff2255ea290d7718da08af30cdf18e470ff7325a5eff63e0057b1496ed66593
|
||||
@@ -591,11 +592,12 @@ F src/test_quota.c 6cb9297115b551f433a9ad1741817a9831abed99
|
||||
F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d
|
||||
F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
|
||||
F src/test_schema.c f5d6067dfc2f2845c4dd56df63e66ee826fb23877855c785f75cc2ca83fd0c1b
|
||||
F src/test_schemapool.c ae21a79f9bc7e9099ae78dbd46d5c28ee75330e62e3256a9fde25564ff9df492
|
||||
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
|
||||
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
|
||||
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
|
||||
F src/test_tclsh.c eeafce33ad2136d57e5dec10f1e9a4347447eb72ffd504a1c7b9c6bfe2e71578
|
||||
F src/test_tclsh.c 6cbaaf30c4fed76c7b35baa42c521fd225c49563ff580f736d77def9e216b31b
|
||||
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
|
||||
F src/test_thread.c 269ea9e1fa5828dba550eb26f619aa18aedbc29fd92f8a5f6b93521fbb74a61c
|
||||
F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43
|
||||
@@ -606,25 +608,25 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
|
||||
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 0b9c82fa628b5adce93e2bcaf935a24d43eb83344fb51551f7835526d0693fc4
|
||||
F src/tokenize.c 8cf83b4b95d09c949e2e4d8f99c0f4bcd955436ef28164f4d4b5f334edaca176
|
||||
F src/treeview.c c6260e1fa5f41c361b2409edc9b0050bcaef5bc4d6abc467fbc45f0d7ccf3d84
|
||||
F src/trigger.c 861c3ec2c5b0fc830bdf82470454a9324fad70cbaa96d2e208fb54577c9e8d28
|
||||
F src/trigger.c 1f4c4ad419bf5ef5e7fa13f0df6db89d8b95f38aa29271e1db9281e55d1fb867
|
||||
F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723
|
||||
F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
|
||||
F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
|
||||
F src/vdbe.c 5001a0d3003d3664615dd7ac3cedab1d51e2391b5bdd0878f40a41fdcd942e13
|
||||
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
|
||||
F src/vacuum.c 724188c5afbba905b310e8d8e78530956d16e6d60a3ba8a1105d05732d7d8601
|
||||
F src/vdbe.c 6d43029157d517ce761c4902d2b543fb8d537dfdd7a8561f95cbe0dd21d4a04d
|
||||
F src/vdbe.h bfde0b0f429a0ba4203e5319780a6a1c8b2a809c5cd6baa9ae22e257a657b8b3
|
||||
F src/vdbeInt.h 000d9ab1ea4cb55a80de15e28f3f595645b4fddef34bca4347fb3db8031d9041
|
||||
F src/vdbeapi.c 4a43e303ec3354c785f453e881521969378e85628278ab74ba4a9df790c0d93b
|
||||
F src/vdbeaux.c 1b3eaa3a70d9d1877266e8ade0d0c3b2b4c6cf77d393d94dbcbd522b9bfefc15
|
||||
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
|
||||
F src/vdbeaux.c 0e12765d38149f203a8e2dc9a79411df0bfa8c0d066acd3b8125effba8009522
|
||||
F src/vdbeblob.c 40028e015fe557a945c99edb6cbf844ea96d853c3e8ac4eb5c1e49bff59f154e
|
||||
F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f
|
||||
F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a
|
||||
F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724
|
||||
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
|
||||
F src/vtab.c 032a0165c147fda16927e6a3230e90c068d4af93f887ce94e26f678fe48e5e4c
|
||||
F src/vtab.c b194210339673cf8a60285f1d87ef2a8055eff32782375ffec842fc6bbacc41a
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 69e770e96fd56cc21608992bf2c6f1f3dc5cf2572d0495c6a643b06c3a679f14
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
@@ -632,8 +634,8 @@ F src/walker.c d42d6c80ea363ef689a462e65eefcfe87deab924c50de5baa37ecb6af7d7ddaa
|
||||
F src/where.c 10d06b16670a1d2a992d52a9f08e49426d38a08fb0a7ae5f7f62fd023d560e1e
|
||||
F src/whereInt.h 446e5e8018f83358ef917cf32d8e6a86dc8430113d0b17e720f1839d3faa44c4
|
||||
F src/wherecode.c e57a8690311a75d06e723e8d379f9831de04aba300e07174d236e32a7f9c7a13
|
||||
F src/whereexpr.c 53452fe2fb07be2f4cb17f55cc721416fae0092c00717f106faf289c990b6494
|
||||
F src/window.c 7e89ac4b6cd6bb9b7772234a625d19c39b530f4ac06e43688a8b7e6a1ab512a2
|
||||
F src/whereexpr.c d8cafcf6781cf871082f04d7540862cf0fe30cb381dd1b2145a380376364fe8e
|
||||
F src/window.c 32b03808aff2e7263889cce0cbcb2a68efefc2a9d5187514ddb6a2a1046dc7f5
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7
|
||||
@@ -649,7 +651,7 @@ F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256b
|
||||
F test/alterauth2.test 794ac5cef251819fe364b4fe20f12f86e9c5d68070513c7fd26c17cb244c89af
|
||||
F test/altercol.test 3456f7cc4196ef8f7d82d245d6e91940eb12bc95c36c91ac4b512f6b5c9a4fa9
|
||||
F test/altercorrupt.test 584d707a80e106952d6382790c8919bcf9f0db678ed3a1c09fd98b7f9d1d3a10
|
||||
F test/alterdropcol.test 596623cb8a72d9570bfb8417b0f302810efe007873796f03c17a9e9ff28dade1
|
||||
F test/alterdropcol.test 7c5199c930d3db8621672265db0cc05bfa87867bae1ee5362f3cf4eaf36c06ba
|
||||
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
|
||||
F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811
|
||||
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
|
||||
@@ -882,7 +884,7 @@ F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650
|
||||
F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
|
||||
F test/exists2.test 3e5726d6a67ebd4bd3466db58be424c09156c1f276c7594abb260cbf6ad494d3
|
||||
F test/exists2.test 47970f2ce98826519cc38ce502b718641755b30a93d9b89915019ba1e770f361
|
||||
F test/existsfault.test 74f7edc713f5a335e7ff47adf503067bf05c6f8630f88b2a19c24f0fa5486ab8
|
||||
F test/expr.test 26cd01e8485bc48c8aa6a1add598e9ce1e706b4eb4f3f554e0b0223022e8c2cf
|
||||
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
|
||||
@@ -1225,7 +1227,7 @@ F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
|
||||
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
|
||||
F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18
|
||||
F test/notnull2.test 965a893619751255e59c911a8c58504b3174a3788b1458b7c7365b232209711b
|
||||
F test/notnull2.test d5e27e7eb9ff80c587998088a3c40dcc9e4faa71c7ec27a41b4435b0f3b8fdc9
|
||||
F test/notnullfault.test 6126e31300632070ca6021698393c7fcf61ab4791bc2aa1d6d704242c0fcd4f8
|
||||
F test/null.test b7ff206a1c60fe01aa2abd33ef9ea83c93727d993ca8a613de86e925c9f2bc6f
|
||||
F test/nulls1.test 82c5bc33148405f21205865abf13c786084438d573a4ac4e87e11b6091cde526
|
||||
@@ -1295,7 +1297,14 @@ F test/releasetest.tcl fb76d8fcc95ac29d6356cd9e52b726ab9e43a24082897618dfbcb7c2b
|
||||
F test/releasetest_data.tcl 3d41ddb3f04f474ac9d925485da24ce6576ff0ebc4c7201c8a340bc09846c261
|
||||
F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/returning1.test 209b910c132cb2015bb1159f852c7124778004963c09095c42c3d2442110c56c
|
||||
F test/returning1.test ce2192b40045cc94d53ac5ec5789a72a3ade233a6ea6e29666e296d151b59479
|
||||
F test/reuse1.test faa2ce5ff566d936b8a10d9e22ba2ee66a54ce89fdcf8aef561df6b15b0ff3d3
|
||||
F test/reuse2.test 5dd9c98579358f0d5a90d25e36dd6e678a03e23446b6c7f2630a8da22ae7ca94
|
||||
F test/reuse3.test 876d15c42d61b1f6ab718cd8169912514ad314d7fe1cd9788080aa62168ba0d1
|
||||
F test/reuse4.test adaad66253aea6cc748674328abe69b650c5c78b8676ed1162d3de09742519f9
|
||||
F test/reuse5.test bbe6cf7384ef90f134392edd93d626385ef0bf6f40eefc3d993535cd0861d83b
|
||||
F test/reuse6.test f4674f9967aee2a0b49c02832120b8b495291c0d87aae084c54e6c0cc18132fe
|
||||
F test/reusefault.test ef646a0fb51d50ddfb4b7cd872f88e7d36eaba64bde7797b3418c3774e1c8d14
|
||||
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
|
||||
F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6
|
||||
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
|
||||
@@ -1336,7 +1345,7 @@ F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test 3d23f66bf9ba77570acfe2ca5f1540ece17037cc64ab1a00efec9758ac29c268
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c
|
||||
F test/select4.test e8a2502e3623f3058871030599a48abb35789d2244d5b380ecf3696873fdd4a4
|
||||
F test/select4.test f0684d3da3bccacbe2a1ebadf6fb49d9df6f53acb4c6ebc228a88d0d6054cc7b
|
||||
F test/select5.test df9ec0d218cedceb4fe7b63262025b547b50a55e59148c6f40b60ca25f1d4546
|
||||
F test/select6.test 319d45e414cdd321bf17cfacedaf19e3935ad64dac357c53f1492338c6e9b801
|
||||
F test/select7.test f659f231489349e8c5734e610803d7654207318f
|
||||
@@ -1440,7 +1449,7 @@ F test/tabfunc01.test 5ca6d004157a3e886a55a9387b960cc0db41acd88753eb597ff409ec6c
|
||||
F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
|
||||
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test 79a473f5797e317c08f2c4f8192edb3eea6a67329b1087453328b66a7cb31070
|
||||
F test/tclsqlite.test 9ad3f8d337ae8e460b25d82094ff1b4f180afc3ca73856ec5a90ac215f43906c
|
||||
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
|
||||
F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440
|
||||
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
@@ -1459,7 +1468,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46
|
||||
F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c a70a8e94bef23339d34226eb9521015ef99f4df8
|
||||
F test/threadtest3.c e63013af10cf236c7610eb06d33bde08c861806dc64be811940ff4d9ddd34a4f
|
||||
F test/threadtest3.c e58f0e1b6a3e4ccb24f831650c296e800f6299cc258793f6fc372591f416cb93
|
||||
F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925
|
||||
F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90
|
||||
F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c
|
||||
@@ -1632,12 +1641,13 @@ F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123
|
||||
F test/triggerG.test 2b816093c91ba73c733cfa8aedcc210ad819d72a98b1da30768a3c56505233e9
|
||||
F test/triggerupfrom.test d25961fa70a99b6736193da7b49a36d8c1d28d56188f0be6406d4366315cd6e4
|
||||
F test/trustschema1.test 4e970aef0bfe0cee139703cc7209d0e0f07725d999b180ba50770f49edef1494
|
||||
F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1
|
||||
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
|
||||
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
|
||||
F test/tt3_checkpoint.c 9a7fe00e07700af027769d83ef67ab727927ae6c865ecdc71fe8011194200c53
|
||||
F test/tt3_index.c 95592839426dc85ce5a7a57b41be2cbf3c2ec3457b9cd841a06ed5877f712c7c
|
||||
F test/tt3_lookaside1.c 2ddd99bfffeef288f0786827ef68f912f6f47ce3d3184e62f05808d8e13b920e
|
||||
F test/tt3_reuseschema.c 4d52e141f89f009028d8ab0bd1f0697d0edffa94bafc1fff0f7ad4d9d9baa549
|
||||
F test/tt3_shared.c b37d22defc944a2ac4c91c927fd06c1d48cd51e2ce9d004fe868625bd2399f93
|
||||
F test/tt3_stress.c f9a769ca8b026ecc76ee93ca8c9700a5619f8e51c581107c4053ba6ac97f616f
|
||||
F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776
|
||||
F test/tt3_stress.c 077e817ac1168443b075fedb44e92db84bb4dc5bd3b6fe1aba25c94ac280b231
|
||||
F test/tt3_vacuum.c ca42adcf8a671abbe34338b828464269e21758a6b4857b889dabfd39a3206d98
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
@@ -1761,7 +1771,7 @@ F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
|
||||
F test/whereL.test 1afe47227f093dc0547236491fb37529b7be9724b8575925a321001b80e6a23a
|
||||
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
|
||||
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
|
||||
F test/wherelimit.test daa0fd9122c5745cc459ec40b8d3c16ce13ce8382b5b847e7cfff4b871260cbf
|
||||
F test/wherelimit.test afb46397c6d7e964e6e294ba3569864a0c570fe3807afc634236c2b752372f31
|
||||
F test/wherelimit2.test 657a3f24aadee62d058c5091ea682dc4af4b95ffe32f137155be49799a58e721
|
||||
F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74
|
||||
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||
@@ -1780,7 +1790,7 @@ F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d761
|
||||
F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
|
||||
F test/window8.tcl f2711aa3571e4e6b0dad98db8d95fd6cb8d9db0c92bbdf535f153b07606a1ce2
|
||||
F test/window8.test c4331b27a6f66d69fa8f8bab10cc731db1a81d293ae108a68f7c3487fa94e65b
|
||||
F test/window9.test 4d8c875b73febdbac9b8f2b52ec132b98f48261cdafd6b08db62bc6d8ff913fc
|
||||
F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836
|
||||
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
|
||||
F test/windowB.test 6e601f8178ba8ba28b2f19e74fe613815084bb4a8d2ad942defc7d42e191e521
|
||||
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
|
||||
@@ -1843,7 +1853,7 @@ F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a89
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
|
||||
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
|
||||
F tool/mkpragmatab.tcl ae5585ae76ca26e4d6ccd5ea9cdebaf5efefb318bf989497a0e846cd711d9ab1
|
||||
F tool/mkpragmatab.tcl 37381569b5a5cd3269e3fdbc08829eb1a5f7c2a8e59ee7be8995127e5ef99e0d
|
||||
F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b7325712
|
||||
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
@@ -1910,7 +1920,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 71e4da136bd1b5b75a699d69fbaaaec0f9dd1a87e2a9d049a55154892b06647b
|
||||
R ae0fc23b03fdb5a4ca6eb2481f79c620
|
||||
U drh
|
||||
Z 141b5de06b8eca068d7463542c326267
|
||||
P 35d1c9a5f846a513a42a0cc9240c3e9a8f3073fa16c88e70b3b9357d8d5adee8 ce8b589e4c7b14ae5f84d47da91931bae109f027490f4b23e0837fde3b037127
|
||||
R 54da8ddc61748361e968710a82a15126
|
||||
U dan
|
||||
Z e72237889cab318d06a88e762bfc81d9
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
6bb2134027a12801de8e0c73482d94682f902024800a7e426614f65a2fe4f64c
|
||||
ca62c36b7f45369679cdc7acfcce108f897d5f7a2ac74bd603b45a024fe5e5bc
|
||||
+16
-5
@@ -87,8 +87,8 @@ static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( v ){
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb, 0, p5);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse, 1, 0, p5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1931,33 +1931,44 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
|
||||
reg = ++pParse->nMem;
|
||||
pParse->nMem += pTab->nCol;
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
|
||||
pParse->nMem += pTab->nCol;
|
||||
}else{
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
pParse->nMem += pPk->nColumn;
|
||||
for(i=0; i<pPk->nKeyCol; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, reg+i+1);
|
||||
}
|
||||
nField = pPk->nKeyCol;
|
||||
}
|
||||
regRec = ++pParse->nMem;
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
|
||||
int regOut;
|
||||
if( pPk ){
|
||||
int iPos = sqlite3TableColumnToIndex(pPk, i);
|
||||
int iColPos = sqlite3TableColumnToIndex(pPk, iCol);
|
||||
if( iPos<pPk->nKeyCol ) continue;
|
||||
regOut = reg+1+iPos-(iPos>iColPos);
|
||||
}else{
|
||||
regOut = reg+1+nField;
|
||||
}
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
|
||||
if( i==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOut);
|
||||
}else{
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
|
||||
}
|
||||
nField++;
|
||||
}
|
||||
}
|
||||
regRec = reg + pTab->nCol;
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec);
|
||||
if( pPk ){
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
|
||||
}
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
@@ -212,6 +212,7 @@ static void openStatTable(
|
||||
** 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
|
||||
);
|
||||
|
||||
+5
-4
@@ -205,14 +205,14 @@ static void attachFunc(
|
||||
** way we found it.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3BtreeEnterAll(db);
|
||||
db->init.iDb = 0;
|
||||
db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
|
||||
if( !REOPEN_AS_MEMDB(db) ){
|
||||
if( !IsSharedSchema(db) && !REOPEN_AS_MEMDB(db) ){
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Init(db, &zErrDyn);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
assert( zErrDyn==0 || rc!=SQLITE_OK );
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
assert( zErrDyn==0 || rc!=SQLITE_OK );
|
||||
}
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){
|
||||
@@ -312,6 +312,7 @@ static void detachFunc(
|
||||
pEntry = sqliteHashNext(pEntry);
|
||||
}
|
||||
|
||||
(void)sqlite3SchemaDisconnect(db, i, 0);
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
|
||||
+86
-58
@@ -325,6 +325,39 @@ int sqlite3UserAuthTable(const char *zTable){
|
||||
}
|
||||
#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
|
||||
@@ -350,59 +383,41 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
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);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash,
|
||||
DFLT_SCHEMA_TABLE);
|
||||
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
if( bUnload ){
|
||||
sqlite3SchemaRelease(db, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}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;
|
||||
/* 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( 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);
|
||||
}
|
||||
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 p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -427,6 +442,7 @@ Table *sqlite3LocateTable(
|
||||
/* 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;
|
||||
@@ -443,8 +459,18 @@ Table *sqlite3LocateTable(
|
||||
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
|
||||
pMod = sqlite3PragmaVtabRegister(db, zName);
|
||||
}
|
||||
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
|
||||
return pMod->pEpoTab;
|
||||
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
|
||||
@@ -454,7 +480,7 @@ Table *sqlite3LocateTable(
|
||||
p = 0;
|
||||
}
|
||||
|
||||
if( 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);
|
||||
@@ -613,11 +639,10 @@ void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
|
||||
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);
|
||||
sqlite3SchemaClearOrDisconnect(db, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -630,16 +655,17 @@ void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
|
||||
void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
for(i=0; i<db->nDb; i=(i?i+1:2)){
|
||||
Db *pDb = &db->aDb[i];
|
||||
if( pDb->pSchema ){
|
||||
if( db->nSchemaLock==0 ){
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
sqlite3SchemaClearOrDisconnect(db, i);
|
||||
}else{
|
||||
DbSetProperty(db, i, DB_ResetWanted);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3SchemaClear(db->aDb[1].pSchema);
|
||||
db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk);
|
||||
sqlite3VtabUnlockList(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
@@ -1135,7 +1161,7 @@ void sqlite3StartTable(
|
||||
*/
|
||||
if( !IN_SPECIAL_PARSE ){
|
||||
char *zDb = db->aDb[iDb].zDbSName;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto begin_table_error;
|
||||
}
|
||||
pTable = sqlite3FindTable(db, zName, zDb);
|
||||
@@ -2641,7 +2667,7 @@ void sqlite3EndTable(
|
||||
#endif
|
||||
|
||||
/* Reparse everything to update our internal data structures */
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
|
||||
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
|
||||
}
|
||||
|
||||
@@ -3171,7 +3197,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
assert( pParse->nErr==0 );
|
||||
assert( pName->nSrc==1 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
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]);
|
||||
@@ -3183,6 +3209,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
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.
|
||||
@@ -3631,7 +3658,7 @@ void sqlite3CreateIndex(
|
||||
if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( sqlite3HasExplicitNulls(pParse, pList) ){
|
||||
@@ -4127,7 +4154,7 @@ void sqlite3CreateIndex(
|
||||
if( pTblName ){
|
||||
sqlite3RefillIndex(pParse, pIndex, iMem);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
}
|
||||
@@ -4276,6 +4303,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
sqlite3SchemaWritable(pParse, iDb);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_INDEX;
|
||||
|
||||
+365
-6
@@ -16,6 +16,63 @@
|
||||
|
||||
#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.
|
||||
@@ -513,15 +570,317 @@ void sqlite3SchemaClear(void *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return the schema associated with a BTree. Create
|
||||
** a new one if necessary.
|
||||
** 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 ){
|
||||
p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
|
||||
Schema *p;
|
||||
if( pBt && IsSharedSchema(db)==0 ){
|
||||
p = (Schema*)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
|
||||
}else{
|
||||
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
|
||||
p = (Schema*)sqlite3DbMallocZero(0, sizeof(Schema));
|
||||
}
|
||||
if( !p ){
|
||||
sqlite3OomFault(db);
|
||||
|
||||
@@ -301,6 +301,9 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_ENABLE_SESSION
|
||||
"ENABLE_SESSION",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_SHARED_SCHEMA
|
||||
"ENABLE_SHARED_SCHEMA",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_SNAPSHOT
|
||||
"ENABLE_SNAPSHOT",
|
||||
#endif
|
||||
|
||||
+20
-6
@@ -958,8 +958,8 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
|
||||
}else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
|
||||
&& !IN_RENAME_OBJECT
|
||||
){
|
||||
sqlite3ExprDelete(db, pLeft);
|
||||
sqlite3ExprDelete(db, pRight);
|
||||
sqlite3ExprDeferredDelete(pParse, pLeft);
|
||||
sqlite3ExprDeferredDelete(pParse, pRight);
|
||||
return sqlite3Expr(db, TK_INTEGER, "0");
|
||||
}else{
|
||||
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
|
||||
@@ -1156,6 +1156,22 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p ) sqlite3ExprDeleteNN(db, p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Arrange to cause pExpr to be deleted when the pParse is deleted.
|
||||
** This is similar to sqlite3ExprDelete() except that the delete is
|
||||
** deferred untilthe pParse is deleted.
|
||||
**
|
||||
** The pExpr might be deleted immediately on an OOM error.
|
||||
**
|
||||
** The deferred delete is (currently) implemented by adding the
|
||||
** pExpr to the pParse->pConstExpr list with a register number of 0.
|
||||
*/
|
||||
void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
|
||||
pParse->pConstExpr =
|
||||
sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
}
|
||||
|
||||
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
|
||||
** expression.
|
||||
*/
|
||||
@@ -5781,8 +5797,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aCol[iAgg].pCExpr = pExpr;
|
||||
pParse->pConstExpr =
|
||||
sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
sqlite3ExprDeferredDelete(pParse, pExpr);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -5791,8 +5806,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
|
||||
pParse->pConstExpr =
|
||||
sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
|
||||
sqlite3ExprDeferredDelete(pParse, pExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1416,9 +1416,9 @@ 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){
|
||||
assert( db==0 || IsVirtual(pTab)
|
||||
|| sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
|
||||
|
||||
/* Remove the FK from the fkeyHash hash table. */
|
||||
if( !db || db->pnBytesFreed==0 ){
|
||||
|
||||
+34
-6
@@ -1159,6 +1159,17 @@ static void disconnectAllVtab(sqlite3 *db){
|
||||
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);
|
||||
@@ -1327,6 +1338,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
if( j!=1 ){
|
||||
sqlite3SchemaDisconnect(db, j, 0);
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
}
|
||||
@@ -3683,7 +3695,7 @@ int sqlite3_table_column_metadata(
|
||||
int *pPrimaryKey, /* OUTPUT: True if column part of PK */
|
||||
int *pAutoinc /* OUTPUT: True if column is auto-increment */
|
||||
){
|
||||
int rc;
|
||||
int rc = SQLITE_OK;
|
||||
char *zErrMsg = 0;
|
||||
Table *pTab = 0;
|
||||
Column *pCol = 0;
|
||||
@@ -3693,7 +3705,7 @@ int sqlite3_table_column_metadata(
|
||||
int notnull = 0;
|
||||
int primarykey = 0;
|
||||
int autoinc = 0;
|
||||
|
||||
int bUnlock;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
|
||||
@@ -3703,14 +3715,29 @@ int sqlite3_table_column_metadata(
|
||||
|
||||
/* Ensure the database schema has been loaded */
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
bUnlock = sqlite3LockReusableSchema(db);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Init(db, &zErrMsg);
|
||||
if( SQLITE_OK!=rc ){
|
||||
goto error_out;
|
||||
if( IsSharedSchema(db)==0 ){
|
||||
rc = sqlite3Init(db, &zErrMsg);
|
||||
}
|
||||
|
||||
/* Locate the table in question */
|
||||
pTab = sqlite3FindTable(db, zTableName, zDbName);
|
||||
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;
|
||||
@@ -3783,6 +3810,7 @@ error_out:
|
||||
sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
|
||||
sqlite3DbFree(db, zErrMsg);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3UnlockReusableSchema(db, bUnlock);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+10
-3
@@ -471,7 +471,13 @@ void sqlite3Pragma(
|
||||
|
||||
/* Make sure the database schema is loaded if the pragma requires that */
|
||||
if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
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 */
|
||||
@@ -1905,9 +1911,10 @@ void sqlite3Pragma(
|
||||
** applications for any purpose.
|
||||
*/
|
||||
case PragTyp_HEADER_VALUE: {
|
||||
int iCookie = pPragma->iArg; /* Which cookie to read or write */
|
||||
int iCookie; /* Which cookie to read or write */
|
||||
iCookie = pPragma->iArg & PRAGMA_HEADER_VALUE_MASK;
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){
|
||||
if( zRight && (pPragma->iArg & PRAGMA_HEADER_VALUE_READONLY)==0 ){
|
||||
/* Write the specified cookie value */
|
||||
static const VdbeOpList setCookie[] = {
|
||||
{ OP_Transaction, 0, 1, 0}, /* 0 */
|
||||
|
||||
+24
-17
@@ -55,12 +55,19 @@
|
||||
#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_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
|
||||
@@ -155,7 +162,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||
{/* zName: */ "auto_vacuum",
|
||||
/* ePragTyp: */ PragTyp_AUTO_VACUUM,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -176,7 +183,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{/* zName: */ "cache_size",
|
||||
/* ePragTyp: */ PragTyp_CACHE_SIZE,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -237,21 +244,21 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
||||
{/* zName: */ "data_version",
|
||||
/* ePragTyp: */ PragTyp_HEADER_VALUE,
|
||||
/* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ BTREE_DATA_VERSION },
|
||||
/* 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,
|
||||
/* 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,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
|
||||
/* ColNames: */ 49, 1,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -288,7 +295,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
|
||||
{/* zName: */ "foreign_key_list",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 8,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -304,9 +311,9 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
||||
{/* zName: */ "freelist_count",
|
||||
/* ePragTyp: */ PragTyp_HEADER_VALUE,
|
||||
/* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ BTREE_FREE_PAGE_COUNT },
|
||||
/* iArg: */ BTREE_FREE_PAGE_COUNT|PRAGMA_HEADER_VALUE_READONLY },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
{/* zName: */ "full_column_names",
|
||||
@@ -346,7 +353,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||
{/* zName: */ "incremental_vacuum",
|
||||
/* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -377,7 +384,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{/* zName: */ "journal_mode",
|
||||
/* ePragTyp: */ PragTyp_JOURNAL_MODE,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "journal_size_limit",
|
||||
@@ -415,7 +422,7 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "max_page_count",
|
||||
/* ePragTyp: */ PragTyp_PAGE_COUNT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "mmap_size",
|
||||
@@ -443,7 +450,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{/* zName: */ "page_count",
|
||||
/* ePragTyp: */ PragTyp_PAGE_COUNT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "page_size",
|
||||
@@ -542,14 +549,14 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
|
||||
{/* zName: */ "stats",
|
||||
/* ePragTyp: */ PragTyp_STATS,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
||||
/* 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,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -633,7 +640,7 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "wal_checkpoint",
|
||||
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_OneSchema,
|
||||
/* ColNames: */ 44, 3,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
|
||||
+126
-10
@@ -38,6 +38,11 @@ static void corruptSchema(
|
||||
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;
|
||||
const char *zObj = azObj[1] ? azObj[1] : "?";
|
||||
@@ -48,6 +53,28 @@ static void corruptSchema(
|
||||
}
|
||||
}
|
||||
|
||||
#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.
|
||||
@@ -71,6 +98,15 @@ static int sqlite3Prepare(
|
||||
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 */
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
@@ -136,7 +172,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
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;
|
||||
@@ -148,7 +188,12 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
if( rc > pData->rc ) pData->rc = rc;
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3OomFault(db);
|
||||
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
|
||||
}else if( rc!=SQLITE_INTERRUPT
|
||||
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
|
||||
&& (rc&0xFF)!=SQLITE_LOCKED
|
||||
&& (rc&0xFF)!=SQLITE_IOERR
|
||||
#endif
|
||||
){
|
||||
corruptSchema(pData, argv, sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
@@ -178,6 +223,12 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
|
||||
if( IsSharedSchema(db) && iDb!=1 ){
|
||||
schemaUpdateChecksum(pData, argv[0], argv[1], argv[2]);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -205,10 +256,28 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
|
||||
assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pSchema );
|
||||
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
|
||||
@@ -229,6 +298,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
initData.mInitFlags = mFlags;
|
||||
initData.nInitRow = 0;
|
||||
initData.cksum = 0;
|
||||
initData.mxPage = 0;
|
||||
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
|
||||
db->mDbFlags &= mask;
|
||||
@@ -239,7 +309,6 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
|
||||
/* Create a cursor to hold the database open
|
||||
*/
|
||||
pDb = &db->aDb[iDb];
|
||||
if( pDb->pBt==0 ){
|
||||
assert( iDb==1 );
|
||||
DbSetProperty(db, 1, DB_SchemaLoaded);
|
||||
@@ -394,6 +463,10 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
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.
|
||||
@@ -415,6 +488,35 @@ error_out:
|
||||
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
|
||||
@@ -425,8 +527,12 @@ error_out:
|
||||
** bit is set in the flags field of the Db structure.
|
||||
*/
|
||||
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
int i, rc;
|
||||
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) );
|
||||
@@ -436,20 +542,19 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
/* 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--){
|
||||
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 ) return rc;
|
||||
}
|
||||
}
|
||||
if( commit_internal ){
|
||||
if( rc==SQLITE_OK && commit_internal ){
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
sqlite3UnlockReusableSchema(db, bReleaseSchema);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -461,11 +566,12 @@ int sqlite3ReadSchema(Parse *pParse){
|
||||
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 ){
|
||||
}else if( db->noSharedCache && !IsSharedSchema(db) ){
|
||||
db->mDbFlags |= DBFLAG_SchemaKnownOk;
|
||||
}
|
||||
}
|
||||
@@ -491,6 +597,10 @@ static void schemaIsValid(Parse *pParse){
|
||||
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. */
|
||||
@@ -780,6 +890,7 @@ static int sqlite3LockAndPrepare(
|
||||
){
|
||||
int rc;
|
||||
int cnt = 0;
|
||||
int bReleaseSchema = 0;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
|
||||
@@ -789,6 +900,7 @@ static int sqlite3LockAndPrepare(
|
||||
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
|
||||
@@ -798,7 +910,11 @@ static int sqlite3LockAndPrepare(
|
||||
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 );
|
||||
db->busyHandler.nBusy = 0;
|
||||
|
||||
+8
-4
@@ -376,15 +376,19 @@ static int lookupName(
|
||||
if( pParse->pTriggerTab!=0 ){
|
||||
int op = pParse->eTriggerOp;
|
||||
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
|
||||
if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){
|
||||
if( pParse->bReturning ){
|
||||
if( (pNC->ncFlags & NC_UBaseReg)!=0
|
||||
&& (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
|
||||
){
|
||||
pExpr->iTable = op!=TK_DELETE;
|
||||
pTab = pParse->pTriggerTab;
|
||||
}
|
||||
}else if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){
|
||||
pExpr->iTable = 1;
|
||||
pTab = pParse->pTriggerTab;
|
||||
}else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){
|
||||
pExpr->iTable = 0;
|
||||
pTab = pParse->pTriggerTab;
|
||||
}else if( pParse->bReturning && (pNC->ncFlags & NC_UBaseReg)!=0 ){
|
||||
pExpr->iTable = op!=TK_DELETE;
|
||||
pTab = pParse->pTriggerTab;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
|
||||
+263
-7
@@ -1152,13 +1152,14 @@ struct ShellState {
|
||||
|
||||
/* 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_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
|
||||
*/
|
||||
@@ -4054,6 +4055,12 @@ static const char *(azHelp[]) = {
|
||||
" --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
|
||||
@@ -4590,6 +4597,11 @@ static void open_db(ShellState *p, int openFlags){
|
||||
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,
|
||||
@@ -6783,6 +6795,237 @@ static char *shellMPrintf(int *pRc, const char *zFmt, ...){
|
||||
}
|
||||
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
|
||||
@@ -8710,6 +8953,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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
|
||||
@@ -9728,6 +9973,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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)
|
||||
@@ -11058,6 +11310,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
#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)
|
||||
@@ -11175,6 +11429,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
#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 ){
|
||||
|
||||
+8
-1
@@ -574,10 +574,11 @@ int sqlite3_exec(
|
||||
#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
|
||||
**
|
||||
@@ -1128,6 +1129,10 @@ struct sqlite3_io_methods {
|
||||
** file to the database file, but before the *-shm file is updated to
|
||||
** record the fact that the pages have been checkpointed.
|
||||
** </ul>
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
|
||||
** Used by the cksmvfs VFS module only.
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
|
||||
@@ -1167,6 +1172,8 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_CKPT_DONE 37
|
||||
#define SQLITE_FCNTL_RESERVE_BYTES 38
|
||||
#define SQLITE_FCNTL_CKPT_START 39
|
||||
#define SQLITE_FCNTL_EXTERNAL_READER 40
|
||||
#define SQLITE_FCNTL_CKSM_FILE 41
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
|
||||
+48
-1
@@ -1141,6 +1141,7 @@ typedef struct CteUse CteUse;
|
||||
typedef struct Db Db;
|
||||
typedef struct DbFixer DbFixer;
|
||||
typedef struct Schema Schema;
|
||||
typedef struct SchemaPool SchemaPool;
|
||||
typedef struct Expr Expr;
|
||||
typedef struct ExprList ExprList;
|
||||
typedef struct FKey FKey;
|
||||
@@ -1277,6 +1278,10 @@ struct Db {
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1308,6 +1313,9 @@ struct Schema {
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1631,6 +1639,12 @@ struct sqlite3 {
|
||||
#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.
|
||||
*/
|
||||
@@ -1711,6 +1725,9 @@ struct sqlite3 {
|
||||
#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
|
||||
@@ -2164,6 +2181,9 @@ struct VTable {
|
||||
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
|
||||
@@ -3454,7 +3474,6 @@ struct Parse {
|
||||
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 */
|
||||
union {
|
||||
int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
|
||||
Returning *pReturning; /* The RETURNING clause */
|
||||
@@ -3621,6 +3640,9 @@ struct 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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3732,6 +3754,7 @@ typedef struct {
|
||||
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;
|
||||
|
||||
@@ -4290,6 +4313,7 @@ Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);
|
||||
void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*);
|
||||
void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
|
||||
void sqlite3ExprDelete(sqlite3*, Expr*);
|
||||
void sqlite3ExprDeferredDelete(Parse*, Expr*);
|
||||
void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
|
||||
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
|
||||
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
|
||||
@@ -4796,6 +4820,29 @@ 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);
|
||||
|
||||
+21
-1
@@ -288,11 +288,24 @@ int sqlite3_db_status(
|
||||
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 = db->aDb[i].pSchema;
|
||||
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;
|
||||
|
||||
@@ -314,7 +327,14 @@ int sqlite3_db_status(
|
||||
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);
|
||||
|
||||
|
||||
@@ -3666,6 +3666,9 @@ static int sqliteCmdUsage(
|
||||
"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;
|
||||
}
|
||||
@@ -3797,6 +3800,16 @@ static int SQLITE_TCLAPI DbMain(
|
||||
}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;
|
||||
|
||||
@@ -770,6 +770,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
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), \
|
||||
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ const char *sqlite3TestInit(Tcl_Interp *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*);
|
||||
@@ -147,6 +148,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
|
||||
Sqlitetest_malloc_Init(interp);
|
||||
Sqlitetest_mutex_Init(interp);
|
||||
Sqlitetestschema_Init(interp);
|
||||
Sqlitetestschemapool_Init(interp);
|
||||
Sqlitetesttclvar_Init(interp);
|
||||
Sqlitetestfs_Init(interp);
|
||||
SqlitetestThread_Init(interp);
|
||||
|
||||
+2
-3
@@ -564,6 +564,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
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
|
||||
@@ -599,7 +600,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
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);
|
||||
@@ -714,8 +714,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
}
|
||||
sqlite3DbFree(db, pParse->pVList);
|
||||
db->pParse = pParse->pParentParse;
|
||||
pParse->pParentParse = 0;
|
||||
db->pParse = pParentParse;
|
||||
assert( nErr==0 || pParse->rc!=SQLITE_OK );
|
||||
return nErr;
|
||||
}
|
||||
|
||||
+53
-4
@@ -62,11 +62,26 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
}
|
||||
pList = pTab->pTrigger;
|
||||
if( pTmpSchema!=pTab->pSchema ){
|
||||
sqlite3 *db = pParse->db;
|
||||
#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) );
|
||||
while( 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))
|
||||
) && 0==sqlite3StrICmp(pTrig->table, pTab->zName)
|
||||
){
|
||||
#else
|
||||
if( pTrig->pTabSchema==pTab->pSchema
|
||||
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
|
||||
){
|
||||
#endif
|
||||
pTrig->pNext = pList;
|
||||
pList = pTrig;
|
||||
}else if( pTrig->op==TK_RETURNING ){
|
||||
@@ -249,6 +264,12 @@ void sqlite3BeginTrigger(
|
||||
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;
|
||||
@@ -355,7 +376,7 @@ void sqlite3FinishTrigger(
|
||||
pTrig->table, z);
|
||||
sqlite3DbFree(db, z);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
|
||||
sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0);
|
||||
}
|
||||
|
||||
@@ -573,6 +594,9 @@ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
|
||||
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);
|
||||
@@ -644,6 +668,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
|
||||
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
|
||||
@@ -823,6 +848,25 @@ SrcList *sqlite3TriggerStepSrc(
|
||||
return pSrc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the pExpr term from the RETURNING clause argument
|
||||
** list is of the form "*". Raise an error if the terms if of the
|
||||
** form "table.*".
|
||||
*/
|
||||
static int isAsteriskTerm(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pTerm /* A term in the RETURNING clause */
|
||||
){
|
||||
assert( pTerm!=0 );
|
||||
if( pTerm->op==TK_ASTERISK ) return 1;
|
||||
if( pTerm->op!=TK_DOT ) return 0;
|
||||
assert( pTerm->pRight!=0 );
|
||||
assert( pTerm->pLeft!=0 );
|
||||
if( pTerm->pRight->op!=TK_ASTERISK ) return 0;
|
||||
sqlite3ErrorMsg(pParse, "RETURNING may not use \"TABLE.*\" wildcards");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The input list pList is the list of result set terms from a RETURNING
|
||||
** clause. The table that we are returning from is pTab.
|
||||
**
|
||||
@@ -840,7 +884,8 @@ static ExprList *sqlite3ExpandReturning(
|
||||
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pOldExpr = pList->a[i].pExpr;
|
||||
if( ALWAYS(pOldExpr!=0) && pOldExpr->op==TK_ASTERISK ){
|
||||
if( NEVER(pOldExpr==0) ) continue;
|
||||
if( isAsteriskTerm(pParse, pOldExpr) ){
|
||||
int jj;
|
||||
for(jj=0; jj<pTab->nCol; jj++){
|
||||
Expr *pNewExpr;
|
||||
@@ -1068,7 +1113,9 @@ static TriggerPrg *codeRowTrigger(
|
||||
Parse *pSubParse; /* Parse context for sub-vdbe */
|
||||
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
|
||||
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger)
|
||||
|| IsSharedSchema(pParse->db)
|
||||
);
|
||||
assert( pTop->pVdbe );
|
||||
|
||||
/* Allocate the TriggerPrg and SubProgram objects. To ensure that they
|
||||
@@ -1176,7 +1223,9 @@ static TriggerPrg *getRowTrigger(
|
||||
Parse *pRoot = sqlite3ParseToplevel(pParse);
|
||||
TriggerPrg *pPrg;
|
||||
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger)
|
||||
|| IsSharedSchema(pParse->db)
|
||||
);
|
||||
|
||||
/* It may be that this trigger has already been coded (or is in the
|
||||
** process of being coded). If this is the case, then an entry with
|
||||
|
||||
@@ -125,6 +125,7 @@ void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
|
||||
}
|
||||
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);
|
||||
|
||||
+7
-7
@@ -3559,13 +3559,6 @@ case OP_Transaction: {
|
||||
&& (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.
|
||||
@@ -3582,6 +3575,13 @@ case OP_Transaction: {
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
|
||||
#else
|
||||
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
|
||||
#endif
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16);
|
||||
void sqlite3VdbeAddParseSchemaOp(Parse*,int,char*,u16);
|
||||
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
|
||||
+3
-1
@@ -471,8 +471,10 @@ void sqlite3VdbeExplainPop(Parse *pParse){
|
||||
** 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, u16 p5){
|
||||
void sqlite3VdbeAddParseSchemaOp(Parse *pParse, int iDb, char *zWhere, u16 p5){
|
||||
Vdbe *p = pParse->pVdbe;
|
||||
int j;
|
||||
sqlite3SchemaWritable(pParse, iDb);
|
||||
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
|
||||
sqlite3VdbeChangeP5(p, p5);
|
||||
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
|
||||
|
||||
@@ -131,7 +131,9 @@ int sqlite3_blob_open(
|
||||
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 ){
|
||||
@@ -148,11 +150,13 @@ int sqlite3_blob_open(
|
||||
|
||||
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;
|
||||
|
||||
@@ -331,6 +335,8 @@ int sqlite3_blob_open(
|
||||
} 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{
|
||||
|
||||
+46
-8
@@ -192,6 +192,24 @@ void sqlite3VtabLock(VTable *pVTab){
|
||||
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;
|
||||
}
|
||||
@@ -489,7 +507,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
|
||||
sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb, zWhere, 0);
|
||||
sqlite3DbFree(db, zStmt);
|
||||
|
||||
iReg = ++pParse->nMem;
|
||||
@@ -563,6 +581,7 @@ static int vtabCallConstructor(
|
||||
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){
|
||||
@@ -579,7 +598,11 @@ static int vtabCallConstructor(
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
|
||||
pVTable = sqlite3MallocZero(sizeof(VTable));
|
||||
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);
|
||||
@@ -587,6 +610,10 @@ static int vtabCallConstructor(
|
||||
}
|
||||
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);
|
||||
@@ -629,12 +656,22 @@ static int vtabCallConstructor(
|
||||
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;
|
||||
** 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], "");
|
||||
@@ -688,6 +725,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||
|
||||
assert( pTab );
|
||||
if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
|
||||
assert( !IsVirtual(pTab) || pTab->nCol>0 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -511,6 +511,7 @@ static void whereCombineDisjuncts(
|
||||
int op; /* Operator for the combined expression */
|
||||
int idxNew; /* Index in pWC of the next virtual term */
|
||||
|
||||
if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return;
|
||||
if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
|
||||
if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
|
||||
if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp
|
||||
@@ -1216,6 +1217,7 @@ static void exprAnalyzeExists(
|
||||
#endif
|
||||
if( pSel->pPrior ) return;
|
||||
if( pSel->pWhere==0 ) return;
|
||||
if( pSel->pLimit ) return;
|
||||
if( 0==exprAnalyzeExistsFindEq(pSel, 0, 0) ) return;
|
||||
|
||||
pDup = sqlite3ExprDup(db, pExpr, 0);
|
||||
|
||||
@@ -1469,6 +1469,7 @@ static void windowCheckValue(Parse *pParse, int reg, int eCond){
|
||||
VdbeCoverageIf(v, eCond==2);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC);
|
||||
VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */
|
||||
VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */
|
||||
VdbeCoverageNeverNullIf(v, eCond==2);
|
||||
|
||||
@@ -276,4 +276,44 @@ do_catchsql_test 6.1 {
|
||||
ALTER TABLE t2 DROP COLUMN z;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
# 2021-04-06 dbsqlfuzz crash-331c5c29bb76257b198f1318eef3288f9624c8ce
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
}
|
||||
do_execsql_test 7.1 {
|
||||
ALTER TABLE t1 DROP COLUMN c;
|
||||
}
|
||||
do_execsql_test 7.2 {
|
||||
SELECT sql FROM sqlite_schema;
|
||||
} {{CREATE TABLE t1(a, b, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID}}
|
||||
do_execsql_test 7.3 {
|
||||
SELECT * FROM t1;
|
||||
} {1 2 4 5}
|
||||
|
||||
foreach {tn wo} {
|
||||
1 {}
|
||||
2 {WITHOUT ROWID}
|
||||
} {
|
||||
reset_db
|
||||
do_execsql_test 9.$tn.0 "
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) $wo;
|
||||
"
|
||||
do_execsql_test 9.$tn.1 {
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000
|
||||
)
|
||||
INSERT INTO t1(a, b, c) SELECT i, 123, 456 FROM s;
|
||||
}
|
||||
do_execsql_test 9.$tn.2 {
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
}
|
||||
|
||||
do_execsql_test 9.$tn.3 {
|
||||
SELECT count(*), c FROM t1 GROUP BY c;
|
||||
} {50000 456}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -164,6 +164,12 @@ do_execsql_test 2.7a {
|
||||
four one
|
||||
}
|
||||
|
||||
do_execsql_test 2.7b {
|
||||
SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE (a,x)=(c,y) LIMIT 1)
|
||||
} {
|
||||
four one
|
||||
}
|
||||
|
||||
# EXISTS clauses using vector expressions in the WHERE clause.
|
||||
#
|
||||
reset_db
|
||||
|
||||
@@ -97,5 +97,17 @@ do_execsql_test 2.1 {
|
||||
SELECT * FROM (SELECT a, b FROM t1) LEFT JOIN t3 ON a IS NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t0(c0 PRIMARY KEY);
|
||||
INSERT INTO t0(c0) VALUES (0);
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT * FROM t0 WHERE ((c0 NOT NULL) AND 1) OR (c0 == NULL);
|
||||
} {0}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -115,5 +115,74 @@ do_execsql_test 5.5 {
|
||||
UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1);
|
||||
} {123}
|
||||
|
||||
# Ticket 132994c8b1063bfb
|
||||
reset_db
|
||||
do_catchsql_test 6.0 {
|
||||
CREATE TABLE t1(id INTEGER PRIMARY KEY);
|
||||
CREATE TABLE t2(x INT, y INT);
|
||||
INSERT INTO t1 VALUES(1),(2),(4),(9);
|
||||
INSERT INTO t2 VALUES(3,7), (4,25), (5,99);
|
||||
UPDATE t1 SET id=id+y FROM t2 WHERE t1.id=t2.x RETURNING t2.*;
|
||||
} {1 {RETURNING may not use "TABLE.*" wildcards}}
|
||||
do_catchsql_test 6.1 {
|
||||
UPDATE t1 SET id=id+y FROM t2 WHERE t1.id=t2.x RETURNING *, '|';
|
||||
SELECT * FROM t1 ORDER BY id;
|
||||
} {0 {29 | 1 2 9 29}}
|
||||
|
||||
# Forum https://sqlite.org/forum/forumpost/85aef8bc01
|
||||
# Do not silently ignore nonsense table names in the RETURNING clause.
|
||||
# Raise an error.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
CREATE TABLE t2(x INT, y INT);
|
||||
INSERT INTO t1(a,b) VALUES(1,2);
|
||||
INSERT INTO t2(x,y) VALUES(1,30);
|
||||
} {}
|
||||
do_catchsql_test 7.2 {
|
||||
UPDATE t1 SET b=b+1 RETURNING new.b;
|
||||
} {1 {no such column: new.b}}
|
||||
do_catchsql_test 7.3 {
|
||||
UPDATE t1 SET b=b+1 RETURNING old.b;
|
||||
} {1 {no such column: old.b}}
|
||||
do_catchsql_test 7.4 {
|
||||
UPDATE t1 SET b=b+1 RETURNING another.b;
|
||||
} {1 {no such column: another.b}}
|
||||
do_catchsql_test 7.5 {
|
||||
UPDATE t1 SET b=b+y FROM t2 WHERE t2.x=t1.a RETURNING t2.x;
|
||||
} {1 {no such column: t2.x}}
|
||||
do_catchsql_test 7.6 {
|
||||
UPDATE t1 SET b=b+y FROM t2 WHERE t2.x=t1.a RETURNING t1.b;
|
||||
} {0 32}
|
||||
|
||||
# This is goofy: The RETURNING clause does not honor the alias
|
||||
# for the table being modified. This might change in the future.
|
||||
#
|
||||
do_catchsql_test 7.7 {
|
||||
UPDATE t1 AS alias SET b=123 RETURNING alias.b;
|
||||
} {1 {no such column: alias.b}}
|
||||
do_catchsql_test 7.8 {
|
||||
UPDATE t1 AS alias SET b=alias.b+1000 RETURNING t1.b;
|
||||
} {0 1032}
|
||||
|
||||
# Forum: https://sqlite.org/forum/info/34c81d83c9177f46
|
||||
reset_db
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE t1(a);
|
||||
CREATE TABLE t2(b,c);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t2 VALUES(3,40);
|
||||
} {}
|
||||
do_catchsql_test 8.2 {
|
||||
INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE new.a=t2.b) AS x;
|
||||
} {1 {no such column: new.a}}
|
||||
do_catchsql_test 8.3 {
|
||||
INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE old.a=t2.b) AS x;
|
||||
} {1 {no such column: old.a}}
|
||||
do_catchsql_test 8.4 {
|
||||
INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE t1.a=t2.b) AS x;
|
||||
} {0 {3 40}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -1025,5 +1025,19 @@ do_execsql_test select4-18.3 {
|
||||
WHERE abs(z1.aa)=z2.aa AND z1.aa=123;
|
||||
} {123}
|
||||
|
||||
# 2021-03-31 Fix an assert() problem in the logic at the end of sqlite3Select()
|
||||
# that validates AggInfo. The checks to ensure that AggInfo.aCol[].pCExpr
|
||||
# references a valid expression was looking at an expression that had been
|
||||
# deleted by the truth optimization in sqlite3ExprAnd() which was invoked by
|
||||
# the push-down optimization. This is harmless in delivery builds, as that code
|
||||
# only runs with SQLITE_DEBUG. But it should still be fixed. The problem
|
||||
# was discovered by dbsqlfuzz (crash-dece7b67a3552ed7e571a7bda903afd1f7bd9b21)
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test select4-19.1 {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(99);
|
||||
SELECT sum((SELECT 1 FROM (SELECT 2 WHERE x IS NULL) WHERE 0)) FROM t1;
|
||||
} {{}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -26,6 +26,9 @@ 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?"
|
||||
}
|
||||
|
||||
+24
-19
@@ -38,7 +38,7 @@
|
||||
#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 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 */
|
||||
@@ -520,11 +520,14 @@ 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 bDelete, /* True to delete db file before opening */
|
||||
int flags
|
||||
){
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
int rc;
|
||||
int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI;
|
||||
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 ){
|
||||
@@ -926,7 +929,7 @@ static char *walthread1_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int nIter = 0; /* Iterations so far */
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
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)",
|
||||
@@ -965,7 +968,7 @@ static char *walthread1_ckpt_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int nCkpt = 0; /* Checkpoints so far */
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
usleep(500*1000);
|
||||
execsql(&err, &db, "PRAGMA wal_checkpoint");
|
||||
@@ -984,7 +987,7 @@ static void walthread1(int nMs){
|
||||
Threadset threads = {0}; /* Test threads */
|
||||
int i; /* Iterator variable */
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"CREATE TABLE t1(x PRIMARY KEY);"
|
||||
@@ -1017,7 +1020,7 @@ static char *walthread2_thread(int iTid, void *pArg){
|
||||
int journal_exists = 0;
|
||||
int wal_exists = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
sql_script(&err, &db, zJournal);
|
||||
clear_error(&err, SQLITE_BUSY);
|
||||
@@ -1047,7 +1050,7 @@ static void walthread2(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db, "CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE)");
|
||||
closedb(&err, &db);
|
||||
|
||||
@@ -1067,7 +1070,7 @@ static char *walthread3_thread(int iTid, void *pArg){
|
||||
i64 iNextWrite; /* Next value this thread will write */
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10");
|
||||
|
||||
iNextWrite = iArg+1;
|
||||
@@ -1104,7 +1107,7 @@ static void walthread3(int nMs){
|
||||
Threadset threads = {0};
|
||||
int i;
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);"
|
||||
@@ -1127,7 +1130,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
integrity_check(&err, &db);
|
||||
}
|
||||
@@ -1142,7 +1145,7 @@ static char *walthread4_writer_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 iRow = 1;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 15;");
|
||||
while( !timetostop(&err) ){
|
||||
execsql_i64(
|
||||
@@ -1162,7 +1165,7 @@ static void walthread4(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);"
|
||||
@@ -1182,7 +1185,7 @@ static char *walthread5_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 nRow;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
nRow = execsql_i64(&err, &db, "SELECT count(*) FROM t1");
|
||||
closedb(&err, &db);
|
||||
|
||||
@@ -1195,7 +1198,7 @@ static void walthread5(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA wal_autocheckpoint = 0;"
|
||||
"PRAGMA page_size = 1024;"
|
||||
@@ -1286,7 +1289,7 @@ static void cgt_pager_1(int nMs){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA cache_size = 2000;"
|
||||
"PRAGMA page_size = 1024;"
|
||||
@@ -1315,7 +1318,7 @@ static char *dynamic_triggers_1(int iTid, void *pArg){
|
||||
int nDrop = 0;
|
||||
int nCreate = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
int i;
|
||||
|
||||
@@ -1368,7 +1371,7 @@ static char *dynamic_triggers_2(int iTid, void *pArg){
|
||||
int nInsert = 0;
|
||||
int nDelete = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
do {
|
||||
iVal = (iVal+1)%100;
|
||||
@@ -1393,7 +1396,7 @@ static void dynamic_triggers(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA page_size = 1024;"
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
@@ -1433,6 +1436,7 @@ static void dynamic_triggers(int nMs){
|
||||
#include "tt3_lookaside1.c"
|
||||
#include "tt3_vacuum.c"
|
||||
#include "tt3_stress.c"
|
||||
#include "tt3_reuseschema.c"
|
||||
#include "tt3_shared.c"
|
||||
|
||||
int main(int argc, char **argv){
|
||||
@@ -1458,6 +1462,7 @@ int main(int argc, char **argv){
|
||||
{ vacuum1, "vacuum1", 10000 },
|
||||
{ stress1, "stress1", 10000 },
|
||||
{ stress2, "stress2", 60000 },
|
||||
{ reuse_schema_1, "reuse_schema_1", 20000 },
|
||||
{ shared1, "shared1", 10000 },
|
||||
};
|
||||
static char *substArgv[] = { 0, "*", 0 };
|
||||
|
||||
@@ -70,7 +70,7 @@ static char *checkpoint_starvation_reader(int iTid, void *pArg){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
i64 iCount1, iCount2;
|
||||
sql_script(&err, &db, "BEGIN");
|
||||
@@ -96,7 +96,7 @@ static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){
|
||||
int nInsert = 0;
|
||||
int i;
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA page_size = 1024;"
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ static char *create_drop_index_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
sql_script(&err, &db,
|
||||
"DROP INDEX IF EXISTS i1;"
|
||||
@@ -51,7 +51,7 @@ static void create_drop_index_1(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
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) "
|
||||
|
||||
@@ -22,7 +22,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
@@ -47,7 +47,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
do{
|
||||
sql_script(&err, &db,
|
||||
@@ -68,7 +68,7 @@ static void lookaside1(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;"
|
||||
"WITH data(x,y) AS ("
|
||||
|
||||
@@ -0,0 +1,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);
|
||||
}
|
||||
+10
-10
@@ -21,7 +21,7 @@ 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);
|
||||
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);
|
||||
@@ -40,7 +40,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
closedb(&err, &db);
|
||||
@@ -59,7 +59,7 @@ static char *stress_thread_3(int iTid, void *pArg){
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;");
|
||||
i1++;
|
||||
@@ -82,11 +82,11 @@ static char *stress_thread_4(int iTid, void *pArg){
|
||||
int i2 = 0;
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
if( iArg ){
|
||||
closedb(&err, &db);
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
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) "
|
||||
@@ -113,12 +113,12 @@ static char *stress_thread_5(int iTid, void *pArg){
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
}
|
||||
execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i);
|
||||
i1++;
|
||||
@@ -265,7 +265,7 @@ static char *stress2_workload19(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
const char *zDb = (const char*)pArg;
|
||||
while( !timetostop(&err) ){
|
||||
opendb(&err, &db, zDb, 0);
|
||||
opendb(&err, &db, zDb, 0, 0);
|
||||
sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
closedb(&err, &db);
|
||||
@@ -290,7 +290,7 @@ static char *stress2_thread_wrapper(int iTid, void *pArg){
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
int cnt;
|
||||
opendb(&err, &db, pCtx->zDb, 0);
|
||||
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);
|
||||
@@ -342,7 +342,7 @@ static void stress2(int nMs){
|
||||
Threadset threads = {0};
|
||||
|
||||
/* To make sure the db file is empty before commencing */
|
||||
opendb(&err, &db, zDb, 1);
|
||||
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);"
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@
|
||||
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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
i64 i = 0;
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
@@ -52,7 +52,7 @@ static char *vacuum1_thread_writer(int iTid, void *pArg){
|
||||
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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
do{
|
||||
sql_script(&err, &db, "VACUUM");
|
||||
@@ -69,7 +69,7 @@ static void vacuum1(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
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);"
|
||||
|
||||
@@ -237,8 +237,8 @@ ifcapable {update_delete_limit} {
|
||||
} {11}
|
||||
create_test_data 6
|
||||
do_test wherelimit-3.2 {
|
||||
execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, old.y, '|' LIMIT 5}
|
||||
} {1 1 | 1 2 | 1 3 | 1 4 | 1 5 |}
|
||||
execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, y, '|' LIMIT 5}
|
||||
} {1 1 | 1 1 | 1 1 | 1 1 | 1 1 |}
|
||||
do_test wherelimit-3.2cnt {
|
||||
execsql {SELECT count(*) FROM t1 WHERE y=1}
|
||||
} {10}
|
||||
|
||||
@@ -265,4 +265,21 @@ do_execsql_test 8.4 {
|
||||
FROM v1;
|
||||
} {0.0 0.0}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(NULL,'bb',356);
|
||||
INSERT INTO t1 VALUES('CB','aa',158);
|
||||
INSERT INTO t1 VALUES('BB','aa',399);
|
||||
INSERT INTO t1 VALUES('FF','bb',938);
|
||||
}
|
||||
|
||||
do_catchsql_test 9.1 {
|
||||
SELECT sum(c) OVER (
|
||||
ORDER BY c RANGE BETWEEN 0 PRECEDING AND '-700' PRECEDING
|
||||
)
|
||||
FROM t1
|
||||
} {1 {frame ending offset must be a non-negative number}}
|
||||
|
||||
finish_test
|
||||
|
||||
+23
-17
@@ -12,7 +12,7 @@
|
||||
|
||||
# Flag meanings:
|
||||
set flagMeaning(NeedSchema) {Force schema load before running}
|
||||
set flagMeaning(ReadOnly) {Read-only HEADER_VALUE}
|
||||
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}
|
||||
@@ -150,7 +150,7 @@ set pragma_def {
|
||||
ARG: SQLITE_CellSizeCk
|
||||
|
||||
NAME: default_cache_size
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
|
||||
COLS: cache_size
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
||||
|
||||
@@ -163,12 +163,12 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: page_count
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: max_page_count
|
||||
TYPE: PAGE_COUNT
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: locking_mode
|
||||
@@ -176,7 +176,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: journal_mode
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: journal_size_limit
|
||||
@@ -184,18 +184,18 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: cache_size
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1
|
||||
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
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
|
||||
IF: !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||
|
||||
NAME: incremental_vacuum
|
||||
FLAG: NeedSchema NoColumns
|
||||
FLAG: NeedSchema NoColumns OneSchema
|
||||
IF: !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||
|
||||
NAME: temp_store
|
||||
@@ -215,7 +215,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
|
||||
|
||||
NAME: synchronous
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: table_info
|
||||
@@ -232,7 +232,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
NAME: stats
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
COLS: tbl idx wdth hght flgs
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
|
||||
|
||||
@@ -256,7 +256,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
NAME: database_list
|
||||
FLAG: NeedSchema Result0
|
||||
FLAG: NeedSchema Result0 OneSchema
|
||||
COLS: seq name file
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
@@ -284,7 +284,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
NAME: foreign_key_list
|
||||
FLAG: NeedSchema Result1 SchemaOpt
|
||||
FLAG: NeedSchema Result1 SchemaOpt OneSchema
|
||||
COLS: id seq table from to on_update on_delete match
|
||||
IF: !defined(SQLITE_OMIT_FOREIGN_KEY)
|
||||
|
||||
@@ -330,14 +330,14 @@ set pragma_def {
|
||||
|
||||
NAME: data_version
|
||||
TYPE: HEADER_VALUE
|
||||
ARG: BTREE_DATA_VERSION
|
||||
FLAG: ReadOnly Result0
|
||||
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
|
||||
FLAG: ReadOnly Result0
|
||||
ARG: BTREE_FREE_PAGE_COUNT|PRAGMA_HEADER_VALUE_READONLY
|
||||
FLAG: Result0
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
||||
|
||||
NAME: application_id
|
||||
@@ -351,7 +351,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
|
||||
|
||||
NAME: wal_checkpoint
|
||||
FLAG: NeedSchema
|
||||
FLAG: NeedSchema OneSchema
|
||||
COLS: busy log checkpointed
|
||||
IF: !defined(SQLITE_OMIT_WAL)
|
||||
|
||||
@@ -510,6 +510,12 @@ foreach f [lsort [array names allflags]] {
|
||||
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} {
|
||||
|
||||
Reference in New Issue
Block a user