Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbc31806a2 | |||
| 25e9591209 | |||
| 6e90771db2 | |||
| 95d398eb12 | |||
| 1a41ff05da | |||
| 2281a15191 | |||
| e9c3e3f788 | |||
| 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 |
@@ -416,6 +416,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 \
|
||||
@@ -472,6 +473,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 \
|
||||
|
||||
@@ -1510,6 +1510,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.30.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.30.1.
|
||||
#
|
||||
#
|
||||
# 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.30.0'
|
||||
PACKAGE_STRING='sqlite 3.30.0'
|
||||
PACKAGE_VERSION='3.30.1'
|
||||
PACKAGE_STRING='sqlite 3.30.1'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1466,7 +1466,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.30.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.30.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1531,7 +1531,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.30.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.30.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1657,7 +1657,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.30.0
|
||||
sqlite configure 3.30.1
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2076,7 +2076,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.30.0, which was
|
||||
It was created by sqlite $as_me 3.30.1, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -12232,7 +12232,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.30.0, which was
|
||||
This file was extended by sqlite $as_me 3.30.1, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12298,7 +12298,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.30.0
|
||||
sqlite config.status 3.30.1
|
||||
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.
|
||||
@@ -59,5 +59,53 @@ do_catchsql_test 1.3.3 {
|
||||
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads'));
|
||||
} {1 {no such cursor: 1}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t0(c0);
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
}
|
||||
do_execsql_test 2.1.1 {
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO vt0(c0) VALUES ('xyz');
|
||||
}
|
||||
do_execsql_test 2.1.2 {
|
||||
ALTER TABLE t0 ADD COLUMN c5;
|
||||
}
|
||||
do_execsql_test 2.1.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 2.1.4 {
|
||||
INSERT INTO vt0(c0) VALUES ('abc');
|
||||
COMMIT
|
||||
}
|
||||
do_execsql_test 2.1.5 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.2.1 {
|
||||
CREATE TABLE t0(c0);
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO vt0(c0) VALUES ('xyz');
|
||||
}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test 2.2.2 {
|
||||
ALTER TABLE t0 RENAME TO t1;
|
||||
}
|
||||
do_execsql_test 2.2.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 2.2.4 {
|
||||
INSERT INTO vt0(c0) VALUES ('abc');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 2.2.5 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -341,6 +341,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 \
|
||||
@@ -392,6 +393,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 Version\s3.30.0
|
||||
D 2019-10-04T15:03:17.190
|
||||
C Merge\sthe\s3.30.1\schanges\sinto\sreuse-schema.
|
||||
D 2019-10-11T11:21:03.165
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 578f123620087ea459aa08fa872810a25ca7c0aaf16331de985bfcddb5f1e747
|
||||
F Makefile.in 4f63722008696418bae434379987f9987cba2ce823579512f2dd5f0ff734c04a
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc a463dca3c50d8a36094fe5c8c39077907f530b54edfc5388c66c85e2cfc8dc04
|
||||
F Makefile.msc bfa3ab0a9d6a81ac5156084c67b75e2c9b66fd543954673ff2135075eef07414
|
||||
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
|
||||
F VERSION 4c516d84c2a5f26c477ed34c09ac4136630f71c68139631f2eb591b22eea7cf1
|
||||
F VERSION 396c1094b353e5533180a7498086557a9c50c76f2bfb62cc5fb69cfba07d562c
|
||||
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 6f5136d2574d7aa08370021ab63be3ef8a8bf32af60594de08393b01feeb4bab x
|
||||
F configure be1e3b2af2355720ff01c2f35fb450ba78488832afffa47452d7c305f333dfa1 x
|
||||
F configure.ac 3552d3aecade98a9d4b64bceb48ffb7726cbc85902efde956812942f060fbd0a
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/lemon.html 24956ab2995e55fe171e55bdd04f22b553957dc8bb43501dbb9311e30187e0d3
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/shared_schema.md 759fc374709fccf4e5d2d0cbd05f8fedd38fb022bdd8a6c5b5f492684c7023b9
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
|
||||
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
|
||||
@@ -189,7 +190,7 @@ F ext/fts5/test/fts5leftjoin.test c0b4cafb9661379e576dc4405c0891d8fcc27826807405
|
||||
F ext/fts5/test/fts5matchinfo.test 79129ff6c9a2d86943b287a5a8caa7ee639f6dcf004d8975d15c279374e82e35
|
||||
F ext/fts5/test/fts5merge.test e92a8db28b45931e7a9c7b1bbd36101692759d00274df74d83fd29d25d53b3a6
|
||||
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
|
||||
F ext/fts5/test/fts5misc.test 5becd134b66f7370042968a2b127b92ea7748e249f16cb6a996f450812e89eec
|
||||
F ext/fts5/test/fts5misc.test 9a7263add42d55b8e22fc6ebbee2904390e923f4aa11d05fffaf617032f95db5
|
||||
F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581
|
||||
F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45
|
||||
F ext/fts5/test/fts5near.test 211477940142d733ac04fad97cb24095513ab2507073a99c2765c3ddd2ef58bd
|
||||
@@ -447,7 +448,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 09716d345766a55b25ed157b14786526cf67c761c61d99c53e117196fb3b391a
|
||||
F main.mk f20c19fda395ae00a77662586eec40ba90aee6b1873ae275a7c2b23ed6d63d48
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -459,9 +460,9 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 5c3031e45e80f79d7d54c2d32dd3c44926544d4f6a478858bfe4ee3191570190
|
||||
F src/analyze.c a3f4ea45cdb4e9df78d4ea7beb87ec8a7a46f494173b641cd28512a40a97bff2
|
||||
F src/attach.c 3ca19504849c2d9be10fc5899d6811f9d6e848665d1a41ffb53df0cd6e7c13ed
|
||||
F src/alter.c 2cd3adaef22863a5d5789b86b662cde97ab66f9c27c7ed86df8c78129d0c5d93
|
||||
F src/analyze.c 050e013f2b1d0f6f334e147c4c0f8a24f4b7dfb83c24fc62a2da7ebb50e45dfb
|
||||
F src/attach.c 6a1a045ff64c542882d1159a1df0aebaeaad86c9ed204edd979e94e8e9feefe1
|
||||
F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
||||
F src/backup.c f70077d40c08b7787bfe934e4d1da8030cb0cc57d46b345fba2294b7d1be23ab
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
@@ -469,17 +470,17 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c fdc4389b271bca30138db27dc2dfb9f52c2a7baaa44845aaf31a3c54663d837f
|
||||
F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89
|
||||
F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f
|
||||
F src/build.c 4814d55abb5553ac82763f6df9e185503d913f912cc0abea00965bb02912cc2d
|
||||
F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73
|
||||
F src/build.c d7bb76a055fb4b44f5d2426ccfe80c8b5b0b1d6de53e71777a2d73f895e4e9a0
|
||||
F src/callback.c 2e6db109a37219464a3a5ed6f2f330af4a0500a1a224122f4be472e454efe2cf
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251
|
||||
F src/ctime.c 15d1010037db3577d2e90e793197c539e86860ab272d7a49e4e976425d0eba62
|
||||
F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041
|
||||
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
|
||||
F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319
|
||||
F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf
|
||||
F src/expr.c 1e9a6da29e3e13c14783891e867e19a54e2731c6a9b58d011cc4f3b4742a59e4
|
||||
F src/expr.c 18974550063a6a1c8eef69e63d2ad88ceb4395ef139a60cc0d0a28632f41d553
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 6b79f4c2447691aa9ac86e2a6a774b65f3b3dd053d4220a4893051a0de20f82e
|
||||
F src/fkey.c 2c14c9431a2de2c0d9444d0cc27e4360f4829455f689decfff01cac383fe0894
|
||||
F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12
|
||||
F src/global.c a1a8d698762ddd9a1543aac26c1e0029b20fcc3fcb56bfa41ec8cea2368f2798
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
@@ -489,7 +490,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 40557ebd69f4115e7a273f9304a8ab637a47ce44f3c6923396928f023967b5e8
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d
|
||||
F src/main.c 3851950717170ade4f6d718c18c6c7400ef5994c2a654679af2cff2ffd0fb2b9
|
||||
F src/main.c dcdd6acc2ec4a790aedf741cb684c43f632c41bbbc34a41129f5cde43437433c
|
||||
F src/malloc.c 0f9da2a66b230a5785af94b9672126845099b57b70a32c987d04ac28c69da990
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -518,23 +519,23 @@ F src/parse.y 50bfcb34be7320dd0cb875021a93ae6451c8f0b083f21b71934a1a3a9108015a
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848
|
||||
F src/pragma.c b47bc7db02ab13d04c680aee424466b4e34f4ef5aa7b2e464876ec005806f98f
|
||||
F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75
|
||||
F src/prepare.c 132484635a30f873ee7eccd47f93ed1932503863b93b28423b42332d81adffaf
|
||||
F src/pragma.c f76a8ddaf4aa0e2dab3c080ad5c9fc4599c3431fe8f2ca36d6a129441e739d1a
|
||||
F src/pragma.h 583d641cfd146d31c91d7ba2770d6b8413c3ff0dc4f4a56645216c983a119c08
|
||||
F src/prepare.c 43e4601125f076d6c30b33c47dfcb3cffcdc1f26f02c4339b6f27c63016c88cd
|
||||
F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c e021be0c1c4a2125fa38aabcd8dbb764bf5b2c889a948c30d3708430ec6ccd00
|
||||
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
|
||||
F src/select.c f509982c96bb24ccf57a0155fbe1e6184e0b8fb8866a04397dc41baa400e5240
|
||||
F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e274
|
||||
F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab
|
||||
F src/select.c b3d64a7a3342471ce078251c5ba132f8ec66f994534f1070dda025b354a09a62
|
||||
F src/shell.c.in 2c49eff321d70abe720d5799f6abfb12c1093dda3956ac813060eb81a5cc8b05
|
||||
F src/sqlite.h.in ba0f0a99948d98adcab93824f6203b50ba81f69c4376cbba8e4e392fd25a8ebe
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31
|
||||
F src/sqliteInt.h 246740eab76d3ac87f856f8d979567089e8749104c12932143a6ba570e38e415
|
||||
F src/sqliteInt.h e2331a36c03c18f4b13444e3502e6cdcb439f97425784733180e8d352b9fdd87
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/status.c d9f7d66ae8bee9ffbe4cf7ae72a8d3d429a269336dee1e705ecb3dbea27fa5e2
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 50c93be3e1c03b4e6cf6756e5197afcfe7f5cd0497d83a7ac317cde09e19b290
|
||||
F src/tclsqlite.c 02d9f47e1797c7aa4174fe90dc5380fb99057303e0b6443fa1b103e9de65cf35
|
||||
F src/test1.c 17e1395cbddeb9226b756d723a7566b45b43b99a5f9f55afb4ff70888de6ad6f
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
@@ -550,7 +551,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 e25826d693039cdd45963de378cbf39e3af0e8aa7a8a6fc159876f4e7b5a4f8c
|
||||
F src/test_config.c 940d67253281cd7a0afba3617bdbd5ba37f5c4d6c3496ab6d6e674ecd056d882
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91
|
||||
F src/test_devsym.c 6109b45c3db3ef7b002320947ed448c027356ab8b885156ff535fd8684d4a571
|
||||
@@ -574,11 +575,12 @@ F src/test_quota.c 6cb9297115b551f433a9ad1741817a9831abed99
|
||||
F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d
|
||||
F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
|
||||
F src/test_schema.c f575932cb6274d12147a77e13ea4b49d52408513
|
||||
F src/test_schemapool.c ae21a79f9bc7e9099ae78dbd46d5c28ee75330e62e3256a9fde25564ff9df492
|
||||
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
|
||||
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 911d15fb14e19c0c542bdc8aabf981c2f10a4858
|
||||
F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43
|
||||
@@ -589,24 +591,24 @@ 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 d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e
|
||||
F src/tokenize.c 3e08eadda7a23a58dd45976c68c600ca2b61a6015c2e61849b1e0cb62f9a9169
|
||||
F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5
|
||||
F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e
|
||||
F src/trigger.c 63761fc1306cf27eb1c875410d23452224ece3aafd14a0b73d6f53776050d06a
|
||||
F src/update.c 7f05fad5e145248a00048aeb0bac78b8fdb4ed17216e14a6eb24c55596e87ee7
|
||||
F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10
|
||||
F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
|
||||
F src/util.c fffdfa627be74d69ef425f92db124e7148af449bb8a3286e79577c42bca84061
|
||||
F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf
|
||||
F src/vdbe.c 7f43ed8e055a4290535d2e4520d33f0ac6cc00ef76a0c099e4c6bd85be74a6b9
|
||||
F src/vdbe.h 3f2b571e702e77e6bf031f0236e554aedfae643e991f69000320f481408455cf
|
||||
F src/vacuum.c 5b9b4771ffb47aaef038c4ad5f1acd76dfbc9e0a4f101c1ba7f7ac9c2ba96374
|
||||
F src/vdbe.c c434e1587c30497e26c3e35758274041c46923efc3c4ee29faec4b3e4a45bdb9
|
||||
F src/vdbe.h 2cfde8249aac55d7f508752e27919e17a30add7bf7444dc221ae5a65d2bafe9d
|
||||
F src/vdbeInt.h e95de5129124d77f01439e6635012adfaf23c0017bff47296126143cf18bd0c6
|
||||
F src/vdbeapi.c 95001d0f84ee3cda344fed98ca0d7961deb4fc836b83495630d0af1f7cc4789e
|
||||
F src/vdbeaux.c 7ccf418141df1c7f87b0d69510523ae522abbe47c769d1b2c15120e88fac3eb9
|
||||
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
|
||||
F src/vdbeaux.c 66d0137de294cadec0dd1d363415bbc0a37416fa9c4ba0b40769a7bbabc02d4b
|
||||
F src/vdbeblob.c 40028e015fe557a945c99edb6cbf844ea96d853c3e8ac4eb5c1e49bff59f154e
|
||||
F src/vdbemem.c d8e10d1773806105e62094c4ede0a4684f46caaf07667a45e6d461e94306b530
|
||||
F src/vdbesort.c da75f505aba230060ce6472605a4aa6494f73eeb1071e1cc2643c3d4035e671b
|
||||
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
|
||||
F src/vtab.c 5a0b7193d586991b3db30e343d6b59959906bfe8658a6a0a85709b20ca50bb49
|
||||
F src/vtab.c 043b188f5f3472935c08686b3f006ca07b26fbacb6eb371f8cd4b06602ab094e
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d
|
||||
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
||||
@@ -859,7 +861,7 @@ F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
|
||||
F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717
|
||||
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
|
||||
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
|
||||
F test/filter1.test c2f34e58ee82a60c3ee9b5b4c4f2004ec2f529dff2f473706eeffa684cbb6719
|
||||
F test/filter1.test edd797ab2ef38de16064c9e3945efd941cba72d27e8f070c349501ff95d2727d
|
||||
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
|
||||
F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a
|
||||
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
|
||||
@@ -1081,7 +1083,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/istrue.test 75327829744e65cc8700e69340b8e6c192e10e39dfae7ccb0e970d3c4f49090a
|
||||
F test/join.test 6ce8296a08e78632c322cde0add78a7ce05466c3d9ec7d5130b38b5b489e7c27
|
||||
F test/join.test 7610c1818f8921618279ab633fc03c93d54f6c8fb9e9e7e96b252319ece346d4
|
||||
F test/join2.test 10f7047e723ebd68b2f47189be8eed20451a6f665d8bf46f1774c640d1062417
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
@@ -1253,6 +1255,13 @@ F test/releasetest.tcl fb76d8fcc95ac29d6356cd9e52b726ab9e43a24082897618dfbcb7c2b
|
||||
F test/releasetest_data.tcl 9919fc6ac5bc92f8878fecfd1840db15999f660a6c9f609240b41aa62b885c88
|
||||
F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/reuse1.test faa2ce5ff566d936b8a10d9e22ba2ee66a54ce89fdcf8aef561df6b15b0ff3d3
|
||||
F test/reuse2.test 5dd9c98579358f0d5a90d25e36dd6e678a03e23446b6c7f2630a8da22ae7ca94
|
||||
F test/reuse3.test ab116714c9dfbdf975716e9dee8409e045e4172dcd0a685275a37b96f370b3bb
|
||||
F test/reuse4.test adaad66253aea6cc748674328abe69b650c5c78b8676ed1162d3de09742519f9
|
||||
F test/reuse5.test bbe6cf7384ef90f134392edd93d626385ef0bf6f40eefc3d993535cd0861d83b
|
||||
F test/reuse6.test 6e188f279a5b2f166fd129a0056285127f2b520add19e044c946bdc3510de9ca
|
||||
F test/reusefault.test ef646a0fb51d50ddfb4b7cd872f88e7d36eaba64bde7797b3418c3774e1c8d14
|
||||
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
|
||||
F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6
|
||||
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
|
||||
@@ -1394,7 +1403,7 @@ F test/tabfunc01.test 20e98ffe55f35d8d33fd834ca8bf9d4b637e560af8fcd00464b4154d90
|
||||
F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
|
||||
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test f9acb83122be0a7c4997ab7f17742507874dced95144c20217c2428553f110bb
|
||||
F test/tclsqlite.test 47dded95a07b8916da62902724ce3a59d60331ed5ba2bfe42d1189ce0413c0f3
|
||||
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
|
||||
F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440
|
||||
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
@@ -1413,7 +1422,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 38a612ea62854349ed66372f330a40d73c5cf956
|
||||
F test/threadtest3.c 4de1edf7cddac6195acfaea56cccb8572df803854531251784f6b8ca46f256e3
|
||||
F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925
|
||||
F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90
|
||||
F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c
|
||||
@@ -1584,11 +1593,12 @@ F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
|
||||
F test/triggerE.test ede2e4bce4ba802337bd69d39447fa04a938e06d84a8bfc53c76850fc36ed86d
|
||||
F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123de3ad
|
||||
F test/triggerG.test d5caeef6144ede2426dd13211fd72248241ff2ebc68e12a4c0bf30f5faa21499
|
||||
F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1
|
||||
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
|
||||
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
|
||||
F test/tt3_stress.c c57d804716165811d979d4a719e05baccd79277f
|
||||
F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776
|
||||
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_stress.c bbd430f23fa64f466ea8f212756f5f7135a2f8ff5accad85550c0ba73be76b16
|
||||
F test/tt3_vacuum.c ca42adcf8a671abbe34338b828464269e21758a6b4857b889dabfd39a3206d98
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
@@ -1707,7 +1717,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
|
||||
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||
F test/window1.test 376a7c9c5b9df9868d92a6d9d455262e1b769f4410b19006f5f8c5507c2a7ed7
|
||||
F test/window1.test 453bb9dcb1b447eddbb4777c97620f02543a4375359723b7372ff09dcf847045
|
||||
F test/window2.tcl 66db96fd9fd202bc31ee7f8ce7904cb469564864cff3f74e009bfef8102333f4
|
||||
F test/window2.test af2a001ded703bb8f2474fb0edfef170d5aba00f5c1f2aa9f65935b5da13df90
|
||||
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
|
||||
@@ -1779,7 +1789,7 @@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
|
||||
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
|
||||
F tool/mkpragmatab.tcl f115d63ada8171f9da28dc8e34e043a1a159692d46b89f66b6e681140bc4683d
|
||||
F tool/mkpragmatab.tcl ee69ec15f46275c873083e7e643adda86b3368cf587dab6b69eb7aa324d8242d
|
||||
F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b7325712
|
||||
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
@@ -1846,10 +1856,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 7f9a4b6015ac332a04d3e394a6b3210fc95253d8786a261178a5639cb8d9d987
|
||||
R f116075cb1c47b7928f41444f3803579
|
||||
T +bgcolor * #d0c0ff
|
||||
T +sym-release *
|
||||
T +sym-version-3.30.0 *
|
||||
P 6e09afecd6086211253b5f8eab718dde097f92a88100e54604a3f063c1a1fc98 18db032d058f1436ce3dea84081f4ee5a0f2259ad97301d43c426bc7f3df1b0b
|
||||
R 72301fc53aaec28cdab85602ae540f06
|
||||
T *branch * reuse-schema-3.30
|
||||
T *sym-reuse-schema-3.30 *
|
||||
T -sym-reuse-schema *
|
||||
U drh
|
||||
Z edadfb0c72633ac9bcd13396063b6815
|
||||
Z d19ae6e90840efaa2320c6bb5a4768e2
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
c20a35336432025445f9f7e289d0cc3e4003fb17f45a4ce74c6269c407c6e09f
|
||||
eff7cd7f12ecbceb452a6e89aad556ba34510f8124295a2aa9273f6d9605b4fe
|
||||
+3
-2
@@ -81,8 +81,8 @@ static void renameReloadSchema(Parse *pParse, int iDb){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( v ){
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb, 0);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,6 +435,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
|
||||
sqlite3MayAbort(pParse);
|
||||
assert( pTab->addColOffset>0 );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
|
||||
@@ -206,6 +206,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
@@ -231,14 +231,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) ){
|
||||
@@ -336,6 +336,7 @@ static void detachFunc(
|
||||
pEntry = sqliteHashNext(pEntry);
|
||||
}
|
||||
|
||||
sqlite3SchemaDisconnect(db, i, 0);
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
|
||||
+69
-12
@@ -287,6 +287,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
|
||||
@@ -316,9 +349,20 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
|
||||
int bUnload = 0;
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
if( IsSharedSchema(db) ){
|
||||
Parse *pParse = db->pParse;
|
||||
if( pParse && pParse->nErr==0 ){
|
||||
pParse->rc = sqlite3SchemaLoad(db, j, &bUnload, &pParse->zErrMsg);
|
||||
if( pParse->rc ) pParse->nErr++;
|
||||
}
|
||||
}
|
||||
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
if( bUnload ){
|
||||
sqlite3SchemaRelease(db, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Not found. If the name we were looking for was temp.sqlite_master
|
||||
@@ -352,6 +396,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;
|
||||
@@ -368,8 +413,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
|
||||
@@ -379,7 +434,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);
|
||||
@@ -538,11 +593,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -555,16 +609,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);
|
||||
@@ -977,7 +1032,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);
|
||||
@@ -2259,7 +2314,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));
|
||||
}
|
||||
|
||||
@@ -2761,7 +2816,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]);
|
||||
@@ -2773,6 +2828,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.
|
||||
@@ -3223,7 +3279,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) ){
|
||||
@@ -3717,7 +3773,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));
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
}
|
||||
@@ -3842,6 +3898,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;
|
||||
|
||||
+364
-6
@@ -16,6 +16,62 @@
|
||||
|
||||
#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;
|
||||
assert( pBt==0 || 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.
|
||||
@@ -465,15 +521,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);
|
||||
|
||||
@@ -295,6 +295,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
|
||||
|
||||
@@ -5146,6 +5146,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
case TK_CASE:
|
||||
case TK_IN:
|
||||
case TK_FUNCTION:
|
||||
case TK_TRUTH:
|
||||
testcase( pExpr->op==TK_ISNOT );
|
||||
testcase( pExpr->op==TK_ISNULL );
|
||||
testcase( pExpr->op==TK_NOTNULL );
|
||||
@@ -5154,6 +5155,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pExpr->op==TK_CASE );
|
||||
testcase( pExpr->op==TK_IN );
|
||||
testcase( pExpr->op==TK_FUNCTION );
|
||||
testcase( pExpr->op==TK_TRUTH );
|
||||
return WRC_Prune;
|
||||
case TK_COLUMN:
|
||||
if( pWalker->u.iCur==pExpr->iTable ){
|
||||
|
||||
+2
-2
@@ -1396,9 +1396,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
@@ -1053,6 +1053,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);
|
||||
@@ -1191,6 +1202,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
if( j!=1 ){
|
||||
sqlite3SchemaDisconnect(db, j, 0);
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
}
|
||||
@@ -3621,7 +3633,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;
|
||||
@@ -3631,7 +3643,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 ){
|
||||
@@ -3641,14 +3653,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;
|
||||
@@ -3721,6 +3748,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
@@ -420,7 +420,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 */
|
||||
@@ -1818,9 +1824,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 */
|
||||
|
||||
+25
-18
@@ -54,12 +54,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
|
||||
@@ -145,7 +152,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
|
||||
@@ -166,7 +173,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
|
||||
@@ -227,21 +234,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: */ 35, 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: */ 45, 1,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -271,14 +278,14 @@ static const PragmaName aPragmaName[] = {
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
{/* zName: */ "foreign_key_check",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_OneSchema,
|
||||
/* ColNames: */ 31, 4,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
|
||||
{/* zName: */ "foreign_key_list",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt|PragFlg_OneSchema,
|
||||
/* ColNames: */ 0, 8,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
@@ -294,9 +301,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",
|
||||
@@ -343,7 +350,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
|
||||
@@ -374,7 +381,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",
|
||||
@@ -424,7 +431,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",
|
||||
@@ -452,7 +459,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",
|
||||
@@ -560,14 +567,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: */ 21, 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
|
||||
@@ -656,7 +663,7 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "wal_checkpoint",
|
||||
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_OneSchema,
|
||||
/* ColNames: */ 38, 3,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
|
||||
+113
-10
@@ -34,6 +34,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;
|
||||
if( zObj==0 ) zObj = "?";
|
||||
@@ -44,6 +49,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.
|
||||
@@ -118,7 +145,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[1], sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
@@ -143,6 +175,12 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
|
||||
if( IsSharedSchema(db) && iDb!=1 ){
|
||||
schemaUpdateChecksum(pData, argv[0], argv[1], argv[2]);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -169,10 +207,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_master or
|
||||
@@ -193,6 +249,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
initData.mInitFlags = mFlags;
|
||||
initData.nInitRow = 0;
|
||||
initData.cksum = 0;
|
||||
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
|
||||
if( initData.rc ){
|
||||
rc = initData.rc;
|
||||
@@ -201,7 +258,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);
|
||||
@@ -357,6 +413,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.
|
||||
@@ -378,6 +438,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
|
||||
@@ -389,8 +478,12 @@ error_out:
|
||||
** file was of zero-length, then the DB_Empty flag is also set.
|
||||
*/
|
||||
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) );
|
||||
@@ -400,20 +493,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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -425,11 +517,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;
|
||||
}
|
||||
}
|
||||
@@ -455,6 +548,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. */
|
||||
@@ -705,6 +802,7 @@ static int sqlite3LockAndPrepare(
|
||||
){
|
||||
int rc;
|
||||
int cnt = 0;
|
||||
int bReleaseSchema = 0;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
|
||||
@@ -714,6 +812,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
|
||||
@@ -723,7 +822,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 );
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
|
||||
+9
-1
@@ -100,9 +100,9 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
|
||||
sqlite3WindowListDelete(db, p->pWinDefn);
|
||||
}
|
||||
assert( p->pWin==0 );
|
||||
#endif
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
||||
assert( p->pWin==0 );
|
||||
if( bFree ) sqlite3DbFreeNN(db, p);
|
||||
p = pPrior;
|
||||
bFree = 1;
|
||||
@@ -3503,6 +3503,14 @@ static Expr *substExpr(
|
||||
}else{
|
||||
substExprList(pSubst, pExpr->x.pList);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
Window *pWin = pExpr->y.pWin;
|
||||
pWin->pFilter = substExpr(pSubst, pWin->pFilter);
|
||||
substExprList(pSubst, pWin->pPartition);
|
||||
substExprList(pSubst, pWin->pOrderBy);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
+264
-7
@@ -1075,13 +1075,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
|
||||
*/
|
||||
@@ -3625,6 +3626,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
|
||||
@@ -4141,6 +4148,11 @@ static void open_db(ShellState *p, int openFlags){
|
||||
sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READONLY, 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(p->zDbFilename, &p->db);
|
||||
@@ -6303,6 +6315,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
|
||||
@@ -8031,6 +8274,9 @@ 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( z[0]=='-' ){
|
||||
#ifdef SQLITE_ENABLE_DESERIALIZE
|
||||
}else if( optionMatch(z, "deserialize") ){
|
||||
p->openMode = SHELL_OPEN_DESERIALIZE;
|
||||
@@ -8983,6 +9229,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)
|
||||
@@ -10261,6 +10514,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;
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
|
||||
}else if( strncmp(z, "-A",2)==0 ){
|
||||
/* All remaining command-line arguments are passed to the ".archive"
|
||||
@@ -10364,6 +10619,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,"-ascii")==0 ){
|
||||
data.mode = MODE_Ascii;
|
||||
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
|
||||
|
||||
@@ -570,6 +570,8 @@ int sqlite3_exec(
|
||||
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
|
||||
|
||||
/* Reserved: 0x00F00000 */
|
||||
#define SQLITE_OPEN_SHARED_SCHEMA 0x01000000 /* Ok for sqlite3_open_v2() */
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Device Characteristics
|
||||
|
||||
+53
-3
@@ -1057,6 +1057,7 @@ typedef struct CollSeq CollSeq;
|
||||
typedef struct Column Column;
|
||||
typedef struct Db Db;
|
||||
typedef struct Schema Schema;
|
||||
typedef struct SchemaPool SchemaPool;
|
||||
typedef struct Expr Expr;
|
||||
typedef struct ExprList ExprList;
|
||||
typedef struct FKey FKey;
|
||||
@@ -1189,6 +1190,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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1220,6 +1225,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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1489,6 +1497,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.
|
||||
*/
|
||||
@@ -1559,6 +1573,9 @@ struct sqlite3 {
|
||||
#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */
|
||||
#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */
|
||||
|
||||
#define DBFLAG_SchemaInuse 0x0020 /* Do not release sharable schemas */
|
||||
#define DBFLAG_FreeSchema 0x0040 /* 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
|
||||
@@ -1946,6 +1963,9 @@ struct VTable {
|
||||
u8 bConstraint; /* True if constraints are supported */
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2585,9 +2605,13 @@ struct Expr {
|
||||
** True if the expression passed as an argument was a function with
|
||||
** an OVER() clause (a window function).
|
||||
*/
|
||||
#define IsWindowFunc(p) ( \
|
||||
#ifdef SQLITE_OMIT_WINDOWFUNC
|
||||
# define IsWindowFunc(p) 0
|
||||
#else
|
||||
# define IsWindowFunc(p) ( \
|
||||
ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \
|
||||
)
|
||||
)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A list of expressions. Each expression may optionally have a
|
||||
@@ -3123,7 +3147,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 */
|
||||
int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
|
||||
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
|
||||
u32 oldmask; /* Mask of old.* columns referenced */
|
||||
@@ -3287,6 +3310,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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3398,6 +3424,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 */
|
||||
} InitData;
|
||||
|
||||
/*
|
||||
@@ -4368,6 +4395,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
@@ -275,11 +275,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;
|
||||
|
||||
@@ -301,7 +314,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);
|
||||
|
||||
|
||||
@@ -3671,6 +3671,9 @@ static int sqliteCmdUsage(
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
|
||||
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
|
||||
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
|
||||
" ?-shared-schema BOOLEAN?"
|
||||
#endif
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
" ?-key CODECKEY?"
|
||||
#endif
|
||||
@@ -3805,6 +3808,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{
|
||||
Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
|
||||
return TCL_ERROR;
|
||||
|
||||
@@ -768,6 +768,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
@@ -560,6 +560,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
|
||||
@@ -595,7 +596,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);
|
||||
@@ -722,8 +722,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
pParse->pZombieTab = p->pNextZombie;
|
||||
sqlite3DeleteTable(db, p);
|
||||
}
|
||||
db->pParse = pParse->pParentParse;
|
||||
pParse->pParentParse = 0;
|
||||
db->pParse = pParentParse;
|
||||
assert( nErr==0 || pParse->rc!=SQLITE_OK );
|
||||
return nErr;
|
||||
}
|
||||
|
||||
+32
-7
@@ -55,15 +55,30 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
}
|
||||
|
||||
if( pTmpSchema!=pTab->pSchema ){
|
||||
sqlite3 *db = pParse->db;
|
||||
HashElem *p;
|
||||
assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) );
|
||||
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
|
||||
char *zSchema = 0;
|
||||
if( IsSharedSchema(db) ){
|
||||
zSchema = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
|
||||
}
|
||||
#endif
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTmpSchema) );
|
||||
for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
|
||||
Trigger *pTrig = (Trigger *)sqliteHashData(p);
|
||||
if( pTrig->pTabSchema==pTab->pSchema
|
||||
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
|
||||
){
|
||||
pTrig->pNext = (pList ? pList : pTab->pTrigger);
|
||||
pList = pTrig;
|
||||
|
||||
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
|
||||
if( (zSchema==0 && pTrig->pTabSchema==pTab->pSchema)
|
||||
|| (zSchema!=0 && 0==sqlite3StrICmp(pTrig->zTabSchema, zSchema)) )
|
||||
#else
|
||||
if( pTrig->pTabSchema==pTab->pSchema )
|
||||
#endif
|
||||
{
|
||||
if( 0==sqlite3StrICmp(pTrig->table, pTab->zName) ){
|
||||
pTrig->pTabSchema = pTab->pSchema;
|
||||
pTrig->pNext = (pList ? pList : pTab->pTrigger);
|
||||
pList = pTrig;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,6 +263,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;
|
||||
@@ -336,7 +357,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));
|
||||
}
|
||||
|
||||
@@ -549,6 +570,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);
|
||||
@@ -620,6 +644,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
|
||||
|
||||
@@ -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);
|
||||
|
||||
+21
-18
@@ -3483,13 +3483,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.
|
||||
@@ -3506,6 +3499,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;
|
||||
}
|
||||
@@ -4538,23 +4538,27 @@ case OP_SeekRowid: { /* jump, in3 */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
testcase( pIn3->flags & MEM_Int );
|
||||
testcase( pIn3->flags & MEM_IntReal );
|
||||
testcase( pIn3->flags & MEM_Real );
|
||||
testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str );
|
||||
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
|
||||
/* Make sure pIn3->u.i contains a valid integer representation of
|
||||
** the key value, but do not change the datatype of the register, as
|
||||
** other parts of the perpared statement might be depending on the
|
||||
** current datatype. */
|
||||
u16 origFlags = pIn3->flags;
|
||||
int isNotInt;
|
||||
applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
|
||||
isNotInt = (pIn3->flags & MEM_Int)==0;
|
||||
pIn3->flags = origFlags;
|
||||
if( isNotInt ) goto jump_to_p2;
|
||||
/* If pIn3->u.i does not contain an integer, compute iKey as the
|
||||
** integer value of pIn3. Jump to P2 if pIn3 cannot be converted
|
||||
** into an integer without loss of information. Take care to avoid
|
||||
** changing the datatype of pIn3, however, as it is used by other
|
||||
** parts of the prepared statement. */
|
||||
Mem x = pIn3[0];
|
||||
applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding);
|
||||
if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
|
||||
iKey = x.u.i;
|
||||
goto notExistsWithKey;
|
||||
}
|
||||
/* Fall through into OP_NotExists */
|
||||
case OP_NotExists: /* jump, in3 */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
iKey = pIn3->u.i;
|
||||
notExistsWithKey:
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -4565,7 +4569,6 @@ case OP_NotExists: /* jump, in3 */
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
res = 0;
|
||||
iKey = pIn3->u.i;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
|
||||
assert( rc==SQLITE_OK || res==0 );
|
||||
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
||||
|
||||
+1
-1
@@ -221,7 +221,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
|
||||
#else
|
||||
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
|
||||
#endif
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
|
||||
void sqlite3VdbeAddParseSchemaOp(Parse*,int,char*);
|
||||
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
|
||||
+4
-2
@@ -410,8 +410,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){
|
||||
void sqlite3VdbeAddParseSchemaOp(Parse *pParse, int iDb, char *zWhere){
|
||||
Vdbe *p = pParse->pVdbe;
|
||||
int j;
|
||||
sqlite3SchemaWritable(pParse, iDb);
|
||||
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
|
||||
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
|
||||
}
|
||||
@@ -640,7 +642,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
int opcode = pOp->opcode;
|
||||
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|
||||
|| opcode==OP_VDestroy
|
||||
|| (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL)
|
||||
|| (opcode==OP_ParseSchema && pOp->p4.z==0)
|
||||
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
||||
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
|
||||
){
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -488,7 +506,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
|
||||
sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb, zWhere);
|
||||
|
||||
iReg = ++pParse->nMem;
|
||||
sqlite3VdbeLoadString(v, iReg, pTab->zName);
|
||||
@@ -561,6 +579,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){
|
||||
@@ -577,7 +596,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);
|
||||
@@ -585,6 +608,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
|
||||
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
|
||||
@@ -626,12 +653,22 @@ static int vtabCallConstructor(
|
||||
int iCol;
|
||||
u8 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], "");
|
||||
@@ -684,6 +721,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||
|
||||
assert( pTab );
|
||||
if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
|
||||
assert( !IsVirtual(pTab) || pTab->nCol>0 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,5 +164,25 @@ do_execsql_test 4.4 {
|
||||
SELECT a, avg(c) FILTER (WHERE b!=1) FROM t1 GROUP BY a ORDER BY 2
|
||||
} {c 2.0 b 5.0 a 10.0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(1, 3);
|
||||
}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
SELECT count(*) FILTER (WHERE b>2) FROM (SELECT * FROM t1)
|
||||
} {1}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
SELECT count(*) FILTER (WHERE b>2) OVER () FROM (SELECT * FROM t1)
|
||||
} {1 1}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
SELECT count(*) FILTER (WHERE b>2) OVER (ORDER BY b) FROM (SELECT * FROM t1)
|
||||
} {0 1}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -884,4 +884,26 @@ do_execsql_test join-17.110 {
|
||||
WHERE NOT(y='a');
|
||||
} {1 3 1 3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test join-18.1 {
|
||||
CREATE TABLE t0(a);
|
||||
CREATE TABLE t1(b);
|
||||
CREATE VIEW v0 AS SELECT a FROM t1 LEFT JOIN t0;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
} {}
|
||||
|
||||
do_execsql_test join-18.2 {
|
||||
SELECT * FROM v0 WHERE NOT(v0.a IS FALSE);
|
||||
} {{}}
|
||||
|
||||
do_execsql_test join-18.3 {
|
||||
SELECT * FROM t1 LEFT JOIN t0 WHERE NOT(a IS FALSE);
|
||||
} {1 {}}
|
||||
|
||||
do_execsql_test join-18.4 {
|
||||
SELECT NOT(v0.a IS FALSE) FROM v0
|
||||
} {1}
|
||||
|
||||
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,354 @@
|
||||
# 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)]
|
||||
expr {$N4 == (($M / 4) + $N-$M)}
|
||||
} 1
|
||||
|
||||
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]
|
||||
expr {$N3==$N1 && $N4==$N1}
|
||||
} {1}
|
||||
|
||||
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
|
||||
|
||||
@@ -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? ?-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"
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct ThreadTest {
|
||||
@@ -1457,6 +1461,7 @@ int main(int argc, char **argv){
|
||||
{ vacuum1, "vacuum1", 10000 },
|
||||
{ stress1, "stress1", 10000 },
|
||||
{ stress2, "stress2", 60000 },
|
||||
{ reuse_schema_1, "reuse_schema_1", 20000 },
|
||||
};
|
||||
static char *substArgv[] = { 0, "*", 0 };
|
||||
int i, iArg;
|
||||
|
||||
@@ -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_master;");
|
||||
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_master;");
|
||||
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);"
|
||||
|
||||
@@ -1190,4 +1190,48 @@ do_execsql_test 30.0 {
|
||||
win3 AS (win2 RANGE BETWEEN 5.2 PRECEDING AND true PRECEDING );
|
||||
} {1 1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 31.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE TABLE t3(e, f);
|
||||
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t2 VALUES(1, 1);
|
||||
INSERT INTO t3 VALUES(1, 1);
|
||||
}
|
||||
|
||||
do_execsql_test 31.2 {
|
||||
SELECT d IN (SELECT sum(c) OVER (ORDER BY e+c) FROM t3) FROM (
|
||||
SELECT * FROM t2
|
||||
);
|
||||
} {1}
|
||||
|
||||
do_execsql_test 31.3 {
|
||||
SELECT d IN (SELECT sum(c) OVER (PARTITION BY d ORDER BY e+c) FROM t3) FROM (
|
||||
SELECT * FROM t2
|
||||
);
|
||||
} {1}
|
||||
|
||||
do_catchsql_test 31.3 {
|
||||
SELECT d IN (
|
||||
SELECT sum(c) OVER ( ROWS BETWEEN d FOLLOWING AND UNBOUNDED FOLLOWING)
|
||||
FROM t3
|
||||
)
|
||||
FROM (
|
||||
SELECT * FROM t2
|
||||
);
|
||||
} {1 {frame starting offset must be a non-negative integer}}
|
||||
|
||||
do_catchsql_test 31.3 {
|
||||
SELECT d IN (
|
||||
SELECT sum(c) OVER ( ROWS BETWEEN CURRENT ROW AND c FOLLOWING)
|
||||
FROM t3
|
||||
)
|
||||
FROM (
|
||||
SELECT * FROM t2
|
||||
);
|
||||
} {1 {frame ending offset must be a non-negative integer}}
|
||||
|
||||
finish_test
|
||||
|
||||
+24
-18
@@ -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,12 +284,12 @@ 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)
|
||||
|
||||
NAME: foreign_key_check
|
||||
FLAG: NeedSchema Result0
|
||||
FLAG: NeedSchema Result0 OneSchema
|
||||
COLS: table rowid parent fkid
|
||||
IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -534,6 +534,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