Compare commits
281 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a925fd256b | |||
| bd50ddeb42 | |||
| 7fd555a634 | |||
| 365e2d255b | |||
| 686138fe88 | |||
| d9e5c4f6ed | |||
| eaf52d883a | |||
| ed36020daf | |||
| 97c1f6c8f2 | |||
| be5481578a | |||
| 5543759b1b | |||
| a10069dd22 | |||
| 09b1330026 | |||
| 7ddccd2aad | |||
| 1c5bb4d69c | |||
| bb23aff3df | |||
| acd0781892 | |||
| ab9b74443c | |||
| 2905f053ef | |||
| e874d9ed79 | |||
| 6a2607a131 | |||
| 005e19c4c1 | |||
| c6315a44b2 | |||
| 65bddc1223 | |||
| 65f2ac58b6 | |||
| 998ad21271 | |||
| 846705021d | |||
| 2c47d194a2 | |||
| 6763e3550d | |||
| 3ebaee9633 | |||
| 72af0774f9 | |||
| fb4a626da0 | |||
| fd06863881 | |||
| 08fba00781 | |||
| 65be0d8cce | |||
| 5273f58f37 | |||
| 576bc3294d | |||
| b7d53f54ae | |||
| 6e5b37faef | |||
| d41a29a653 | |||
| 84aab39782 | |||
| a861469a07 | |||
| c9e4665e7d | |||
| ff6dfc73fe | |||
| e404de05c0 | |||
| 24e3971197 | |||
| 9a6b4e9adb | |||
| 8f6097c244 | |||
| 5def0843f1 | |||
| ccd13d1f80 | |||
| c7991bdf29 | |||
| 5c10f77d52 | |||
| 4bc79def36 | |||
| 3289c5efc8 | |||
| 1018e90b1e | |||
| 16adb77623 | |||
| 811bdbd206 | |||
| fc34ad291e | |||
| 92d7652379 | |||
| 7721b23e0a | |||
| a8e654eb38 | |||
| cd058ec4ef | |||
| 33bec22fb1 | |||
| 2cee6abf8e | |||
| b6e099a973 | |||
| ef37802545 | |||
| 8d6ad1cc2c | |||
| d0b2677b78 | |||
| d5e6e4004b | |||
| 324e46d424 | |||
| 0dcb0a7d7b | |||
| 5e9e482fe0 | |||
| 529b18706d | |||
| 76ed3bc044 | |||
| 4c846bb148 | |||
| 1fbe0f2a8f | |||
| af0cfd366a | |||
| b7e8ea2015 | |||
| e8e1c9d50e | |||
| 6fcff07f6a | |||
| b033d8b9dc | |||
| 87c1fe1b69 | |||
| 5a299f9134 | |||
| 11398e5e54 | |||
| 586b9c8a94 | |||
| 2d536e187f | |||
| f72a8751c9 | |||
| bee6f4ebe2 | |||
| 77b95a379c | |||
| 5cf53537a8 | |||
| 057f1ecddb | |||
| 7aba8fdef7 | |||
| bb16ff75dd | |||
| d80b233850 | |||
| 27d52b2b19 | |||
| be837bddad | |||
| 6dea3248ae | |||
| 1b48aa49a4 | |||
| fe05aa144c | |||
| c9d53dbe5a | |||
| 400df2ea70 | |||
| 43a56b812c | |||
| 78daa5a7d9 | |||
| 30c8629e67 | |||
| 6ddb4bf938 | |||
| 49156b2b5e | |||
| d749084ad0 | |||
| a7ad518ef0 | |||
| 6045461eee | |||
| 5530b764a8 | |||
| 87bfb51ef8 | |||
| 1bc6171c23 | |||
| e93808dde2 | |||
| 4c97b53425 | |||
| ba51590bcd | |||
| 5047af405b | |||
| 79e6c78ccc | |||
| 6908343c65 | |||
| 7ed91f2344 | |||
| 31cbbbad1c | |||
| 7b6944047e | |||
| 185cca609b | |||
| 31c03907fd | |||
| b4e3a6f72f | |||
| e45d442692 | |||
| f032f5362e | |||
| 5e0ce87a3f | |||
| 9beb1584bd | |||
| 833bf968e3 | |||
| 4b64c1e365 | |||
| 8b348af860 | |||
| 8b5444bfae | |||
| af75c8695b | |||
| e106de6317 | |||
| 31f98fc8e4 | |||
| 29d4beccc0 | |||
| 8c6f666b26 | |||
| e180c296ea | |||
| 93791ea0ba | |||
| c6d2b4a365 | |||
| 4cd78b4d89 | |||
| 7ecc14761e | |||
| 562cedb185 | |||
| 71cb518fca | |||
| cd11fb28c3 | |||
| c438efd68a | |||
| f2424c521b | |||
| a4741840f6 | |||
| 56d95913eb | |||
| 74d6cd887f | |||
| 9de7943783 | |||
| 545f587fc8 | |||
| 4f08d4b848 | |||
| ff207012e6 | |||
| 3306c4a945 | |||
| 9a6e897328 | |||
| d5c99c3939 | |||
| ce4f05f374 | |||
| ede6eb8d1d | |||
| b978002743 | |||
| a470aeb4ac | |||
| 28e5386f79 | |||
| e04dc88be5 | |||
| 8d22a17411 | |||
| 54934f4689 | |||
| c511878955 | |||
| 335c0faabd | |||
| dea0a85091 | |||
| 6703239d2f | |||
| 3674bfd1b6 | |||
| 3de777fd8c | |||
| 4b93f6bd1e | |||
| 97a313554d | |||
| 4a4b01dc1c | |||
| f391327824 | |||
| 4cc6fb6165 | |||
| bb2e9c97fc | |||
| ed808acd1b | |||
| 521a72b1fa | |||
| 39c79f587c | |||
| ce2f88d95b | |||
| ed754ce2cc | |||
| 1e0f4a83d6 | |||
| 49320f8568 | |||
| e264d983d1 | |||
| 02bb596649 | |||
| b9bf16bfde | |||
| 64d039e512 | |||
| 622194c0d2 | |||
| f05c86dd73 | |||
| 80a1526a9a | |||
| d3f8f94652 | |||
| 9281bf2a9f | |||
| 835ae8bcdd | |||
| c9206ed56e | |||
| 08ede1d08b | |||
| 09c0f6d02d | |||
| 02927cc1f3 | |||
| 63ca1dba52 | |||
| 6700d02cce | |||
| 7c24610e64 | |||
| eada58aa49 | |||
| 47f18f7294 | |||
| 91781bd72f | |||
| f762593eaa | |||
| 05f69dd388 | |||
| 6498f0bb2e | |||
| 9e48165b07 | |||
| f12cde5637 | |||
| c71b5f34c9 | |||
| 7caba669a6 | |||
| 8bd5412b90 | |||
| 67ae0cb231 | |||
| 52ff8ea605 | |||
| 9d6caca80d | |||
| 5c56f70199 | |||
| 0013e72edf | |||
| 5a8aedab2d | |||
| d14133e3f4 | |||
| 3c379b0101 | |||
| c633908199 | |||
| 4139c99eba | |||
| 2a6a7eeba5 | |||
| ab5cd70ae5 | |||
| 0a7a9155a4 | |||
| a21a64dd0c | |||
| 75bb9f5a5b | |||
| 424aab88ca | |||
| 8b307fbfa0 | |||
| 25d3adbb6a | |||
| 8d83c0fdd5 | |||
| 34e2b837d5 | |||
| a378c566d2 | |||
| c2a4bab462 | |||
| cce75d3343 | |||
| 4d077f9255 | |||
| 43377f5ad5 | |||
| 45b355dc4f | |||
| 9afb1abe42 | |||
| 1f5b467f13 | |||
| a792dc5c4a | |||
| 8d8626fe2b | |||
| afc266a76a | |||
| 67a6a40cf9 | |||
| d3d986d329 | |||
| 4b4580b701 | |||
| 97b59a56d2 | |||
| b1299158c7 | |||
| bf59283ba2 | |||
| 7ba4597135 | |||
| d454214ddd | |||
| 4b11b0897a | |||
| 25a80ad0b1 | |||
| 5e0ccc216d | |||
| dd3cd977cc | |||
| c26c00495f | |||
| 1141ae2463 | |||
| 6d3cb2fbae | |||
| 280799b4ff | |||
| 7bca0a3660 | |||
| d6291c9155 | |||
| 486ff4897e | |||
| e07b606522 | |||
| bb23e7f91b | |||
| acd63a5a62 | |||
| 98f0c3619f | |||
| f3609eeba7 | |||
| 3f0d9d3846 | |||
| f92a4e35c5 | |||
| e9c2d34c5b | |||
| ba726f4939 | |||
| 3b6f4c06ac | |||
| 71663ad0c1 | |||
| 3a3dd3ac8d | |||
| 9396a41e6e | |||
| ed37690afd | |||
| 107b56e86d | |||
| 735b9cbb96 | |||
| 63da089314 | |||
| 9f8da32662 | |||
| c92271c549 |
+11
-2
@@ -176,7 +176,7 @@ OBJS0 = alter.lo analyze.lo attach.lo auth.lo backup.lo bitvec.lo btmutex.lo \
|
||||
table.lo tokenize.lo trigger.lo update.lo \
|
||||
util.lo vacuum.lo \
|
||||
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbetrace.lo \
|
||||
walker.lo where.lo utf.lo vtab.lo
|
||||
wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
|
||||
# Object files for the amalgamation.
|
||||
#
|
||||
@@ -276,6 +276,8 @@ SRC = \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/vdbeInt.h \
|
||||
$(TOP)/src/vtab.c \
|
||||
$(TOP)/src/wal.c \
|
||||
$(TOP)/src/wal.h \
|
||||
$(TOP)/src/walker.c \
|
||||
$(TOP)/src/where.c
|
||||
|
||||
@@ -339,8 +341,8 @@ TESTSRC2 = \
|
||||
$(TOP)/src/bitvec.c \
|
||||
$(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/expr.c \
|
||||
$(TOP)/src/func.c \
|
||||
$(TOP)/src/insert.c \
|
||||
@@ -365,6 +367,8 @@ TESTSRC2 = \
|
||||
$(TOP)/src/vdbeaux.c \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/wal.c \
|
||||
$(TOP)/src/wal.h \
|
||||
$(TOP)/src/where.c \
|
||||
parse.c
|
||||
|
||||
@@ -385,6 +389,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_backup.c \
|
||||
$(TOP)/src/test_btree.c \
|
||||
$(TOP)/src/test_config.c \
|
||||
$(TOP)/src/test_demovfs.c \
|
||||
$(TOP)/src/test_devsym.c \
|
||||
$(TOP)/src/test_func.c \
|
||||
$(TOP)/src/test_hexio.c \
|
||||
@@ -400,6 +405,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_wsd.c
|
||||
|
||||
# Header files used by all library source files.
|
||||
@@ -742,6 +748,9 @@ vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR)
|
||||
vtab.lo: $(TOP)/src/vtab.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c
|
||||
|
||||
wal.lo: $(TOP)/src/wal.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wal.c
|
||||
|
||||
walker.lo: $(TOP)/src/walker.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/walker.c
|
||||
|
||||
|
||||
@@ -386,6 +386,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_wsd.c \
|
||||
|
||||
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.6.23.1.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.7.0.
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.6.23.1'
|
||||
PACKAGE_STRING='sqlite 3.6.23.1'
|
||||
PACKAGE_VERSION='3.7.0'
|
||||
PACKAGE_STRING='sqlite 3.7.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -1487,7 +1487,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.6.23.1 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.7.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1552,7 +1552,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.6.23.1:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1670,7 +1670,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.6.23.1
|
||||
sqlite configure 3.7.0
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1684,7 +1684,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.6.23.1, which was
|
||||
It was created by sqlite $as_me 3.7.0, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -13972,7 +13972,7 @@ exec 6>&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.6.23.1, which was
|
||||
This file was extended by sqlite $as_me 3.7.0, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -14025,7 +14025,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.6.23.1
|
||||
sqlite config.status 3.7.0
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
@@ -14458,7 +14458,8 @@ $debug ||
|
||||
if test -n "$CONFIG_FILES"; then
|
||||
|
||||
|
||||
ac_cr='
'
|
||||
ac_cr='
|
||||
'
|
||||
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
|
||||
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
|
||||
ac_cs_awk_cr='\\r'
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
*** Throughout this document, a page is deemed to have been synced
|
||||
automatically as soon as it is written when PRAGMA synchronous=OFF.
|
||||
Otherwise, the page is not synced until the xSync method of the VFS
|
||||
is called successfully on the file containing the page.
|
||||
|
||||
*** Definition: A page of the database file is said to be "overwriteable" if
|
||||
one or more of the following are true about the page:
|
||||
|
||||
(a) The original content of the page as it was at the beginning of
|
||||
the transaction has been written into the rollback journal and
|
||||
synced.
|
||||
|
||||
(b) The page was a freelist leaf page at the start of the transaction.
|
||||
|
||||
(c) The page number is greater than the largest page that existed in
|
||||
the database file at the start of the transaction.
|
||||
|
||||
(1) A page of the database file is never overwritten unless one of the
|
||||
following are true:
|
||||
|
||||
(a) The page and all other pages on the same sector are overwriteable.
|
||||
|
||||
(b) The atomic page write optimization is enabled, and the entire
|
||||
transaction other than the update of the transaction sequence
|
||||
number consists of a single page change.
|
||||
|
||||
(2) The content of a page written into the rollback journal exactly matches
|
||||
both the content in the database when the rollback journal was written
|
||||
and the content in the database at the beginning of the current
|
||||
transaction.
|
||||
|
||||
(3) Writes to the database file are an integer multiple of the page size
|
||||
in length and are aligned to a page boundary.
|
||||
|
||||
(4) Reads from the database file are either aligned on a page boundary and
|
||||
an integer multiple of the page size in length or are taken from the
|
||||
first 100 bytes of the database file.
|
||||
|
||||
(5) All writes to the database file are synced prior to the rollback journal
|
||||
being deleted, truncated, or zeroed.
|
||||
|
||||
(6) If a master journal file is used, then all writes to the database file
|
||||
are synced prior to the master journal being deleted.
|
||||
|
||||
*** Definition: Two databases (or the same database at two points it time)
|
||||
are said to be "logically equivalent" if they give the same answer to
|
||||
all queries. Note in particular the the content of freelist leaf
|
||||
pages can be changed arbitarily without effecting the logical equivalence
|
||||
of the database.
|
||||
|
||||
(7) At any time, if any subset, including the empty set and the total set,
|
||||
of the unsynced changes to a rollback journal are removed and the
|
||||
journal is rolled back, the resulting database file will be logical
|
||||
equivalent to the database file at the beginning of the transaction.
|
||||
|
||||
(8) When a transaction is rolled back, the xTruncate method of the VFS
|
||||
is called to restore the database file to the same size it was at
|
||||
the beginning of the transaction. (In some VFSes, the xTruncate
|
||||
method is a no-op, but that does not change the fact the SQLite will
|
||||
invoke it.)
|
||||
|
||||
(9) Whenever the database file is modified, at least one bit in the range
|
||||
of bytes from 24 through 39 inclusive will be changed prior to releasing
|
||||
the EXCLUSIVE lock.
|
||||
|
||||
(10) The pattern of bits in bytes 24 through 39 shall not repeat in less
|
||||
than one billion transactions.
|
||||
|
||||
(11) A database file is well-formed at the beginning and at the conclusion
|
||||
of every transaction.
|
||||
|
||||
(12) An EXCLUSIVE lock must be held on the database file before making
|
||||
any changes to the database file.
|
||||
|
||||
(13) A SHARED lock must be held on the database file before reading any
|
||||
content out of the database file.
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
The 5 states of an historical rollback lock as implemented by the
|
||||
xLock, xUnlock, and xCheckReservedLock methods of the sqlite3_io_methods
|
||||
objec are:
|
||||
|
||||
UNLOCKED
|
||||
SHARED
|
||||
RESERVED
|
||||
PENDING
|
||||
EXCLUSIVE
|
||||
|
||||
The wal-index file has a similar locking hierarchy implemented using
|
||||
the xShmLock method of the sqlite3_vfs object, but with 7
|
||||
states. Each connection to a wal-index file must be in one of
|
||||
the following 7 states:
|
||||
|
||||
UNLOCKED
|
||||
READ
|
||||
READ_FULL
|
||||
WRITE
|
||||
PENDING
|
||||
CHECKPOINT
|
||||
RECOVER
|
||||
|
||||
These roughly correspond to the 5 states of a rollback lock except
|
||||
that SHARED is split out into 2 states: READ and READ_FULL and
|
||||
there is an extra RECOVER state used for wal-index reconstruction.
|
||||
|
||||
The meanings of the various wal-index locking states is as follows:
|
||||
|
||||
UNLOCKED - The wal-index is not in use.
|
||||
|
||||
READ - Some prefix of the wal-index is being read. Additional
|
||||
wal-index information can be appended at any time. The
|
||||
newly appended content will be ignored by the holder of
|
||||
the READ lock.
|
||||
|
||||
READ_FULL - The entire wal-index is being read. No new information
|
||||
can be added to the wal-index. The holder of a READ_FULL
|
||||
lock promises never to read pages from the database file
|
||||
that are available anywhere in the wal-index.
|
||||
|
||||
WRITE - It is OK to append to the wal-index file and to adjust
|
||||
the header to indicate the new "last valid frame".
|
||||
|
||||
PENDING - Waiting on all READ locks to clear so that a
|
||||
CHECKPOINT lock can be acquired.
|
||||
|
||||
CHECKPOINT - It is OK to write any WAL data into the database file
|
||||
and zero the last valid frame field of the wal-index
|
||||
header. The wal-index file itself may not be changed
|
||||
other than to zero the last valid frame field in the
|
||||
header.
|
||||
|
||||
RECOVER - Held during wal-index recovery. Used to prevent a
|
||||
race if multiple clients try to recover a wal-index at
|
||||
the same time.
|
||||
|
||||
|
||||
A particular lock manager implementation may coalesce one or more of
|
||||
the wal-index locking states, though with a reduction in concurrency.
|
||||
For example, an implemention might implement only exclusive locking,
|
||||
in which case all states would be equivalent to CHECKPOINT, meaning that
|
||||
only one reader or one writer or one checkpointer could be active at a
|
||||
time. Or, an implementation might combine READ and READ_FULL into
|
||||
a single state equivalent to READ, meaning that a writer could
|
||||
coexist with a reader, but no reader or writers could coexist with a
|
||||
checkpointer.
|
||||
|
||||
The lock manager must obey the following rules:
|
||||
|
||||
(1) A READ cannot coexist with CHECKPOINT.
|
||||
(2) A READ_FULL cannot coexist with WRITE.
|
||||
(3) None of WRITE, PENDING, CHECKPOINT, or RECOVER can coexist.
|
||||
|
||||
The SQLite core will obey the next set of rules. These rules are
|
||||
assertions on the behavior of the SQLite core which might be verified
|
||||
during testing using an instrumented lock manager.
|
||||
|
||||
(5) No part of the wal-index will be read without holding either some
|
||||
kind of SHM lock or an EXCLUSIVE lock on the original database.
|
||||
The original database is the file named in the 2nd parameter to
|
||||
the xShmOpen method.
|
||||
|
||||
(6) A holder of a READ_FULL will never read any page of the database
|
||||
file that is contained anywhere in the wal-index.
|
||||
|
||||
(7) No part of the wal-index other than the header will be written nor
|
||||
will the size of the wal-index grow without holding a WRITE or
|
||||
an EXCLUSIVE on the original database file.
|
||||
|
||||
(8) The wal-index header will not be written without holding one of
|
||||
WRITE, CHECKPOINT, or RECOVER on the wal-index or an EXCLUSIVE on
|
||||
the original database files.
|
||||
|
||||
(9) A CHECKPOINT or RECOVER must be held on the wal-index, or an
|
||||
EXCLUSIVE on the original database file, in order to reset the
|
||||
last valid frame counter in the header of the wal-index back to zero.
|
||||
|
||||
(10) A WRITE can only increase the last valid frame pointer in the header.
|
||||
|
||||
The SQLite core will only ever send requests for UNLOCK, READ, WRITE,
|
||||
CHECKPOINT, or RECOVER to the lock manager. The SQLite core will never
|
||||
request a READ_FULL or PENDING lock though the lock manager may deliver
|
||||
those locking states in response to READ and CHECKPOINT requests,
|
||||
respectively, if and only if the requested READ or CHECKPOINT cannot
|
||||
be delivered.
|
||||
|
||||
The following are the allowed lock transitions:
|
||||
|
||||
Original-State Request New-State
|
||||
-------------- ---------- ----------
|
||||
(11a) UNLOCK READ READ
|
||||
(11b) UNLOCK READ READ_FULL
|
||||
(11c) UNLOCK CHECKPOINT PENDING
|
||||
(11d) UNLOCK CHECKPOINT CHECKPOINT
|
||||
(11e) READ UNLOCK UNLOCK
|
||||
(11f) READ WRITE WRITE
|
||||
(11g) READ RECOVER RECOVER
|
||||
(11h) READ_FULL UNLOCK UNLOCK
|
||||
(11i) READ_FULL WRITE WRITE
|
||||
(11j) READ_FULL RECOVER RECOVER
|
||||
(11k) WRITE READ READ
|
||||
(11l) PENDING UNLOCK UNLOCK
|
||||
(11m) PENDING CHECKPOINT CHECKPOINT
|
||||
(11n) CHECKPOINT UNLOCK UNLOCK
|
||||
(11o) RECOVER READ READ
|
||||
|
||||
These 15 transitions are all that needs to be supported. The lock
|
||||
manager implementation can assert that fact. The other 27 possible
|
||||
transitions among the 7 locking states will never occur.
|
||||
+138
-72
@@ -48,7 +48,7 @@
|
||||
** This is similar in concept to how sqlite encodes "varints" but
|
||||
** the encoding is not the same. SQLite varints are big-endian
|
||||
** are are limited to 9 bytes in length whereas FTS3 varints are
|
||||
** little-endian and can be upt to 10 bytes in length (in theory).
|
||||
** little-endian and can be up to 10 bytes in length (in theory).
|
||||
**
|
||||
** Example encodings:
|
||||
**
|
||||
@@ -59,26 +59,26 @@
|
||||
**
|
||||
**** Document lists ****
|
||||
** A doclist (document list) holds a docid-sorted list of hits for a
|
||||
** given term. Doclists hold docids, and can optionally associate
|
||||
** token positions and offsets with docids. A position is the index
|
||||
** of a word within the document. The first word of the document has
|
||||
** a position of 0.
|
||||
** given term. Doclists hold docids and associated token positions.
|
||||
** A docid is the unique integer identifier for a single document.
|
||||
** A position is the index of a word within the document. The first
|
||||
** word of the document has a position of 0.
|
||||
**
|
||||
** FTS3 used to optionally store character offsets using a compile-time
|
||||
** option. But that functionality is no longer supported.
|
||||
**
|
||||
** A DL_POSITIONS_OFFSETS doclist is stored like this:
|
||||
** A doclist is stored like this:
|
||||
**
|
||||
** array {
|
||||
** varint docid;
|
||||
** array { (position list for column 0)
|
||||
** varint position; (delta from previous position plus POS_BASE)
|
||||
** varint position; (2 more than the delta from previous position)
|
||||
** }
|
||||
** array {
|
||||
** varint POS_COLUMN; (marks start of position list for new column)
|
||||
** varint column; (index of new column)
|
||||
** array {
|
||||
** varint position; (delta from previous position plus POS_BASE)
|
||||
** varint position; (2 more than the delta from previous position)
|
||||
** }
|
||||
** }
|
||||
** varint POS_END; (marks end of positions for this document.
|
||||
@@ -90,7 +90,7 @@
|
||||
** in the same logical place as the position element, and act as sentinals
|
||||
** ending a position list array. POS_END is 0. POS_COLUMN is 1.
|
||||
** The positions numbers are not stored literally but rather as two more
|
||||
** the difference from the prior position, or the just the position plus
|
||||
** than the difference from the prior position, or the just the position plus
|
||||
** 2 for the first position. Example:
|
||||
**
|
||||
** label: A B C D E F G H I J K
|
||||
@@ -104,14 +104,14 @@
|
||||
** 234 at I is the next docid. It has one position 72 (72-2) and then
|
||||
** terminates with the 0 at K.
|
||||
**
|
||||
** A DL_POSITIONS doclist omits the startOffset and endOffset
|
||||
** information. A DL_DOCIDS doclist omits both the position and
|
||||
** offset information, becoming an array of varint-encoded docids.
|
||||
**
|
||||
** On-disk data is stored as type DL_DEFAULT, so we don't serialize
|
||||
** the type. Due to how deletion is implemented in the segmentation
|
||||
** system, on-disk doclists MUST store at least positions.
|
||||
** A "position-list" is the list of positions for multiple columns for
|
||||
** a single docid. A "column-list" is the set of positions for a single
|
||||
** column. Hence, a position-list consists of one or more column-lists,
|
||||
** a document record consists of a docid followed by a position-list and
|
||||
** a doclist consists of one or more document records.
|
||||
**
|
||||
** A bare doclist omits the position information, becoming an
|
||||
** array of varint-encoded docids.
|
||||
**
|
||||
**** Segment leaf nodes ****
|
||||
** Segment leaf nodes store terms and doclists, ordered by term. Leaf
|
||||
@@ -359,8 +359,7 @@ int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes required to store the value passed as the
|
||||
** first argument in varint form.
|
||||
** Return the number of bytes required to encode v as a varint
|
||||
*/
|
||||
int sqlite3Fts3VarintLen(sqlite3_uint64 v){
|
||||
int i = 0;
|
||||
@@ -411,7 +410,7 @@ void sqlite3Fts3Dequote(char *z){
|
||||
|
||||
/*
|
||||
** Read a single varint from the doclist at *pp and advance *pp to point
|
||||
** to the next element of the varlist. Add the value of the varint
|
||||
** to the first byte past the end of the varint. Add the value of the varint
|
||||
** to *pVal.
|
||||
*/
|
||||
static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){
|
||||
@@ -467,7 +466,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
|
||||
**
|
||||
** If *pRc is initially non-zero then this routine is a no-op.
|
||||
*/
|
||||
void fts3DbExec(
|
||||
static void fts3DbExec(
|
||||
int *pRc, /* Success code */
|
||||
sqlite3 *db, /* Database in which to run SQL */
|
||||
const char *zFormat, /* Format string for SQL */
|
||||
@@ -547,6 +546,10 @@ static int fts3DeclareVtab(Fts3Table *p){
|
||||
** Create the backing store tables (%_content, %_segments and %_segdir)
|
||||
** required by the FTS3 table passed as the only argument. This is done
|
||||
** as part of the vtab xCreate() method.
|
||||
**
|
||||
** If the p->bHasDocsize boolean is true (indicating that this is an
|
||||
** FTS4 table, not an FTS3 table) then also create the %_docsize and
|
||||
** %_stat tables required by FTS4.
|
||||
*/
|
||||
static int fts3CreateTables(Fts3Table *p){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
@@ -639,7 +642,7 @@ static void fts3TableExists(
|
||||
**
|
||||
** The argv[] array contains the following:
|
||||
**
|
||||
** argv[0] -> module name
|
||||
** argv[0] -> module name ("fts3" or "fts4")
|
||||
** argv[1] -> database name
|
||||
** argv[2] -> table name
|
||||
** argv[...] -> "column name" and other module argument fields.
|
||||
@@ -658,12 +661,12 @@ static int fts3InitVtab(
|
||||
int rc; /* Return code */
|
||||
int i; /* Iterator variable */
|
||||
int nByte; /* Size of allocation used for *p */
|
||||
int iCol;
|
||||
int nString = 0;
|
||||
int nCol = 0;
|
||||
char *zCsr;
|
||||
int nDb;
|
||||
int nName;
|
||||
int iCol; /* Column index */
|
||||
int nString = 0; /* Bytes required to hold all column names */
|
||||
int nCol = 0; /* Number of columns in the FTS table */
|
||||
char *zCsr; /* Space for holding column names */
|
||||
int nDb; /* Bytes required to hold database name */
|
||||
int nName; /* Bytes required to hold table name */
|
||||
|
||||
const char *zTokenizer = 0; /* Name of tokenizer to use */
|
||||
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
|
||||
@@ -893,6 +896,11 @@ static int fulltextClose(sqlite3_vtab_cursor *pCursor){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Position the pCsr->pStmt statement so that it is on the row
|
||||
** of the %_content table that contains the last match. Return
|
||||
** SQLITE_OK on success.
|
||||
*/
|
||||
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
||||
if( pCsr->isRequireSeek ){
|
||||
pCsr->isRequireSeek = 0;
|
||||
@@ -919,6 +927,17 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Advance the cursor to the next row in the %_content table that
|
||||
** matches the search criteria. For a MATCH search, this will be
|
||||
** the next row that matches. For a full-table scan, this will be
|
||||
** simply the next row in the %_content table. For a docid lookup,
|
||||
** this routine simply sets the EOF flag.
|
||||
**
|
||||
** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
|
||||
** even if we reach end-of-file. The fts3EofMethod() will be called
|
||||
** subsequently to determine whether or not an EOF was hit.
|
||||
*/
|
||||
static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
|
||||
@@ -1055,6 +1074,11 @@ static void fts3PutDeltaVarint(
|
||||
** start of a position-list. After it returns, *ppPoslist points to the
|
||||
** first byte after the position-list.
|
||||
**
|
||||
** A position list is list of positions (delta encoded) and columns for
|
||||
** a single document record of a doclist. So, in other words, this
|
||||
** routine advances *ppPoslist so that it points to the next docid in
|
||||
** the doclist, or to the first byte past the end of the doclist.
|
||||
**
|
||||
** If pp is not NULL, then the contents of the position list are copied
|
||||
** to *pp. *pp is set to point to the first byte past the last byte copied
|
||||
** before this function returns.
|
||||
@@ -1064,17 +1088,20 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
|
||||
char c = 0;
|
||||
|
||||
/* The end of a position list is marked by a zero encoded as an FTS3
|
||||
** varint. A single 0x00 byte. Except, if the 0x00 byte is preceded by
|
||||
** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by
|
||||
** a byte with the 0x80 bit set, then it is not a varint 0, but the tail
|
||||
** of some other, multi-byte, value.
|
||||
**
|
||||
** The following block moves pEnd to point to the first byte that is not
|
||||
** The following while-loop moves pEnd to point to the first byte that is not
|
||||
** immediately preceded by a byte with the 0x80 bit set. Then increments
|
||||
** pEnd once more so that it points to the byte immediately following the
|
||||
** last byte in the position-list.
|
||||
*/
|
||||
while( *pEnd | c ) c = *pEnd++ & 0x80;
|
||||
pEnd++;
|
||||
while( *pEnd | c ){
|
||||
c = *pEnd++ & 0x80;
|
||||
testcase( c!=0 && (*pEnd)==0 );
|
||||
}
|
||||
pEnd++; /* Advance past the POS_END terminator byte */
|
||||
|
||||
if( pp ){
|
||||
int n = (int)(pEnd - *ppPoslist);
|
||||
@@ -1086,12 +1113,34 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
|
||||
*ppPoslist = pEnd;
|
||||
}
|
||||
|
||||
/*
|
||||
** When this function is called, *ppPoslist is assumed to point to the
|
||||
** start of a column-list. After it returns, *ppPoslist points to the
|
||||
** to the terminator (POS_COLUMN or POS_END) byte of the column-list.
|
||||
**
|
||||
** A column-list is list of delta-encoded positions for a single column
|
||||
** within a single document within a doclist.
|
||||
**
|
||||
** The column-list is terminated either by a POS_COLUMN varint (1) or
|
||||
** a POS_END varint (0). This routine leaves *ppPoslist pointing to
|
||||
** the POS_COLUMN or POS_END that terminates the column-list.
|
||||
**
|
||||
** If pp is not NULL, then the contents of the column-list are copied
|
||||
** to *pp. *pp is set to point to the first byte past the last byte copied
|
||||
** before this function returns. The POS_COLUMN or POS_END terminator
|
||||
** is not copied into *pp.
|
||||
*/
|
||||
static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
|
||||
char *pEnd = *ppPoslist;
|
||||
char c = 0;
|
||||
|
||||
/* A column-list is terminated by either a 0x01 or 0x00. */
|
||||
while( 0xFE & (*pEnd | c) ) c = *pEnd++ & 0x80;
|
||||
/* A column-list is terminated by either a 0x01 or 0x00 byte that is
|
||||
** not part of a multi-byte varint.
|
||||
*/
|
||||
while( 0xFE & (*pEnd | c) ){
|
||||
c = *pEnd++ & 0x80;
|
||||
testcase( c!=0 && ((*pEnd)&0xfe)==0 );
|
||||
}
|
||||
if( pp ){
|
||||
int n = (int)(pEnd - *ppPoslist);
|
||||
char *p = *pp;
|
||||
@@ -1103,37 +1152,45 @@ static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
|
||||
}
|
||||
|
||||
/*
|
||||
** Value used to signify the end of an offset-list. This is safe because
|
||||
** Value used to signify the end of an position-list. This is safe because
|
||||
** it is not possible to have a document with 2^31 terms.
|
||||
*/
|
||||
#define OFFSET_LIST_END 0x7fffffff
|
||||
#define POSITION_LIST_END 0x7fffffff
|
||||
|
||||
/*
|
||||
** This function is used to help parse offset-lists. When this function is
|
||||
** called, *pp may point to the start of the next varint in the offset-list
|
||||
** being parsed, or it may point to 1 byte past the end of the offset-list
|
||||
** (in which case **pp will be 0x00 or 0x01).
|
||||
** This function is used to help parse position-lists. When this function is
|
||||
** called, *pp may point to the start of the next varint in the position-list
|
||||
** being parsed, or it may point to 1 byte past the end of the position-list
|
||||
** (in which case **pp will be a terminator bytes POS_END (0) or
|
||||
** (1)).
|
||||
**
|
||||
** If *pp points past the end of the current offset list, set *pi to
|
||||
** OFFSET_LIST_END and return. Otherwise, read the next varint from *pp,
|
||||
** If *pp points past the end of the current position-list, set *pi to
|
||||
** POSITION_LIST_END and return. Otherwise, read the next varint from *pp,
|
||||
** increment the current value of *pi by the value read, and set *pp to
|
||||
** point to the next value before returning.
|
||||
**
|
||||
** Before calling this routine *pi must be initialized to the value of
|
||||
** the previous position, or zero if we are reading the first position
|
||||
** in the position-list. Because positions are delta-encoded, the value
|
||||
** of the previous position is needed in order to compute the value of
|
||||
** the next position.
|
||||
*/
|
||||
static void fts3ReadNextPos(
|
||||
char **pp, /* IN/OUT: Pointer into offset-list buffer */
|
||||
sqlite3_int64 *pi /* IN/OUT: Value read from offset-list */
|
||||
char **pp, /* IN/OUT: Pointer into position-list buffer */
|
||||
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
|
||||
){
|
||||
if( **pp&0xFE ){
|
||||
if( (**pp)&0xFE ){
|
||||
fts3GetDeltaVarint(pp, pi);
|
||||
*pi -= 2;
|
||||
}else{
|
||||
*pi = OFFSET_LIST_END;
|
||||
*pi = POSITION_LIST_END;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If parameter iCol is not 0, write an 0x01 byte followed by the value of
|
||||
** iCol encoded as a varint to *pp.
|
||||
** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by
|
||||
** the value of iCol encoded as a varint to *pp. This will start a new
|
||||
** column list.
|
||||
**
|
||||
** Set *pp to point to the byte just after the last byte written before
|
||||
** returning (do not modify it if iCol==0). Return the total number of bytes
|
||||
@@ -1151,7 +1208,11 @@ static int fts3PutColNumber(char **pp, int iCol){
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** Compute the union of two position lists. The output written
|
||||
** into *pp contains all positions of both *pp1 and *pp2 in sorted
|
||||
** order and with any duplicates removed. All pointers are
|
||||
** updated appropriately. The caller is responsible for insuring
|
||||
** that there is enough space in *pp to hold the complete output.
|
||||
*/
|
||||
static void fts3PoslistMerge(
|
||||
char **pp, /* Output buffer */
|
||||
@@ -1163,32 +1224,33 @@ static void fts3PoslistMerge(
|
||||
char *p2 = *pp2;
|
||||
|
||||
while( *p1 || *p2 ){
|
||||
int iCol1;
|
||||
int iCol2;
|
||||
int iCol1; /* The current column index in pp1 */
|
||||
int iCol2; /* The current column index in pp2 */
|
||||
|
||||
if( *p1==0x01 ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
|
||||
else if( *p1==0x00 ) iCol1 = OFFSET_LIST_END;
|
||||
if( *p1==POS_COLUMN ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
|
||||
else if( *p1==POS_END ) iCol1 = POSITION_LIST_END;
|
||||
else iCol1 = 0;
|
||||
|
||||
if( *p2==0x01 ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
|
||||
else if( *p2==0x00 ) iCol2 = OFFSET_LIST_END;
|
||||
if( *p2==POS_COLUMN ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
|
||||
else if( *p2==POS_END ) iCol2 = POSITION_LIST_END;
|
||||
else iCol2 = 0;
|
||||
|
||||
if( iCol1==iCol2 ){
|
||||
sqlite3_int64 i1 = 0;
|
||||
sqlite3_int64 i2 = 0;
|
||||
sqlite3_int64 i1 = 0; /* Last position from pp1 */
|
||||
sqlite3_int64 i2 = 0; /* Last position from pp2 */
|
||||
sqlite3_int64 iPrev = 0;
|
||||
int n = fts3PutColNumber(&p, iCol1);
|
||||
p1 += n;
|
||||
p2 += n;
|
||||
|
||||
/* At this point, both p1 and p2 point to the start of offset-lists.
|
||||
** An offset-list is a list of non-negative delta-encoded varints, each
|
||||
** incremented by 2 before being stored. Each list is terminated by a 0
|
||||
** or 1 value (0x00 or 0x01). The following block merges the two lists
|
||||
/* At this point, both p1 and p2 point to the start of column-lists
|
||||
** for the same column (the column with index iCol1 and iCol2).
|
||||
** A column-list is a list of non-negative delta-encoded varints, each
|
||||
** incremented by 2 before being stored. Each list is terminated by a
|
||||
** POS_END (0) or POS_COLUMN (1). The following block merges the two lists
|
||||
** and writes the results to buffer p. p is left pointing to the byte
|
||||
** after the list written. No terminator (0x00 or 0x01) is written to
|
||||
** the output.
|
||||
** after the list written. No terminator (POS_END or POS_COLUMN) is
|
||||
** written to the output.
|
||||
*/
|
||||
fts3GetDeltaVarint(&p1, &i1);
|
||||
fts3GetDeltaVarint(&p2, &i2);
|
||||
@@ -1203,7 +1265,7 @@ static void fts3PoslistMerge(
|
||||
}else{
|
||||
fts3ReadNextPos(&p2, &i2);
|
||||
}
|
||||
}while( i1!=OFFSET_LIST_END || i2!=OFFSET_LIST_END );
|
||||
}while( i1!=POSITION_LIST_END || i2!=POSITION_LIST_END );
|
||||
}else if( iCol1<iCol2 ){
|
||||
p1 += fts3PutColNumber(&p, iCol1);
|
||||
fts3ColumnlistCopy(&p, &p1);
|
||||
@@ -1213,7 +1275,7 @@ static void fts3PoslistMerge(
|
||||
}
|
||||
}
|
||||
|
||||
*p++ = '\0';
|
||||
*p++ = POS_END;
|
||||
*pp = p;
|
||||
*pp1 = p1 + 1;
|
||||
*pp2 = p2 + 1;
|
||||
@@ -1236,11 +1298,11 @@ static int fts3PoslistPhraseMerge(
|
||||
int iCol1 = 0;
|
||||
int iCol2 = 0;
|
||||
assert( *p1!=0 && *p2!=0 );
|
||||
if( *p1==0x01 ){
|
||||
if( *p1==POS_COLUMN ){
|
||||
p1++;
|
||||
p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
|
||||
}
|
||||
if( *p2==0x01 ){
|
||||
if( *p2==POS_COLUMN ){
|
||||
p2++;
|
||||
p2 += sqlite3Fts3GetVarint32(p2, &iCol2);
|
||||
}
|
||||
@@ -1253,11 +1315,12 @@ static int fts3PoslistPhraseMerge(
|
||||
sqlite3_int64 iPos2 = 0;
|
||||
|
||||
if( pp && iCol1 ){
|
||||
*p++ = 0x01;
|
||||
*p++ = POS_COLUMN;
|
||||
p += sqlite3Fts3PutVarint(p, iCol1);
|
||||
}
|
||||
|
||||
assert( *p1!=0x00 && *p2!=0x00 && *p1!=0x01 && *p2!=0x01 );
|
||||
assert( *p1!=POS_END && *p1!=POS_COLUMN );
|
||||
assert( *p2!=POS_END && *p2!=POS_COLUMN );
|
||||
fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2;
|
||||
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
|
||||
|
||||
@@ -1509,6 +1572,7 @@ static int fts3DoclistMerge(
|
||||
default: assert( mergetype==MERGE_POS_NEAR || mergetype==MERGE_NEAR ); {
|
||||
char *aTmp = 0;
|
||||
char **ppPos = 0;
|
||||
|
||||
if( mergetype==MERGE_POS_NEAR ){
|
||||
ppPos = &p;
|
||||
aTmp = sqlite3_malloc(2*(n1+n2+1));
|
||||
@@ -1613,9 +1677,9 @@ static int fts3TermSelectCb(
|
||||
**
|
||||
** The returned doclist may be in one of two formats, depending on the
|
||||
** value of parameter isReqPos. If isReqPos is zero, then the doclist is
|
||||
** a sorted list of delta-compressed docids. If isReqPos is non-zero,
|
||||
** then the returned list is in the same format as is stored in the
|
||||
** database without the found length specifier at the start of on-disk
|
||||
** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
|
||||
** is non-zero, then the returned list is in the same format as is stored
|
||||
** in the database without the found length specifier at the start of on-disk
|
||||
** doclists.
|
||||
*/
|
||||
static int fts3TermSelect(
|
||||
@@ -1875,7 +1939,9 @@ int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
|
||||
|
||||
/*
|
||||
** Evaluate the full-text expression pExpr against fts3 table pTab. Store
|
||||
** the resulting doclist in *paOut and *pnOut.
|
||||
** the resulting doclist in *paOut and *pnOut. This routine mallocs for
|
||||
** the space needed to store the output. The caller is responsible for
|
||||
** freeing the space when it has finished.
|
||||
*/
|
||||
static int evalFts3Expr(
|
||||
Fts3Table *p, /* Virtual table handle */
|
||||
|
||||
@@ -53,6 +53,20 @@
|
||||
*/
|
||||
#define FTS3_VARINT_MAX 10
|
||||
|
||||
/*
|
||||
** The testcase() macro is only used by the amalgamation. If undefined,
|
||||
** make it a no-op.
|
||||
*/
|
||||
#ifndef testcase
|
||||
# define testcase(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Terminator values for position-lists and column-lists.
|
||||
*/
|
||||
#define POS_COLUMN (1) /* Column-list terminator */
|
||||
#define POS_END (0) /* Position-list terminator */
|
||||
|
||||
/*
|
||||
** This section provides definitions to allow the
|
||||
** FTS3 extension to be compiled outside of the
|
||||
|
||||
@@ -571,7 +571,7 @@ static int fts3StringAppend(
|
||||
** is no way for fts3BestSnippet() to know whether or not the document
|
||||
** actually contains terms that follow the final highlighted term.
|
||||
*/
|
||||
int fts3SnippetShift(
|
||||
static int fts3SnippetShift(
|
||||
Fts3Table *pTab, /* FTS3 table snippet comes from */
|
||||
int nSnippet, /* Number of tokens desired for snippet */
|
||||
const char *zDoc, /* Document text to extract snippet from */
|
||||
|
||||
@@ -2483,6 +2483,7 @@ static int rtreeUpdate(
|
||||
}
|
||||
rc = sqlite3_reset(pRtree->pReadRowid);
|
||||
}
|
||||
*pRowid = cell.iRowid;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
|
||||
|
||||
@@ -399,4 +399,21 @@ do_test rtree-10.1 {
|
||||
catchsql { CREATE VIRTUAL TABLE t7 USING rtree(index, x1, y1, x2, y2) }
|
||||
} {1 {near "index": syntax error}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test last_insert_rowid().
|
||||
#
|
||||
do_test rtree-11.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t8 USING rtree(idx, x1, x2, y1, y2);
|
||||
INSERT INTO t8 VALUES(1, 1.0, 1.0, 2.0, 2.0);
|
||||
SELECT last_insert_rowid();
|
||||
}
|
||||
} {1}
|
||||
do_test rtree-11.2 {
|
||||
execsql {
|
||||
INSERT INTO t8 VALUES(NULL, 1.0, 1.0, 2.0, 2.0);
|
||||
SELECT last_insert_rowid();
|
||||
}
|
||||
} {2}
|
||||
|
||||
finish_test
|
||||
|
||||
Regular → Executable
@@ -66,7 +66,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
|
||||
table.o tokenize.o trigger.o \
|
||||
update.o util.o vacuum.o \
|
||||
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbetrace.o \
|
||||
walker.o where.o utf.o vtab.o
|
||||
wal.o walker.o where.o utf.o vtab.o
|
||||
|
||||
|
||||
|
||||
@@ -158,6 +158,8 @@ SRC = \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/vdbeInt.h \
|
||||
$(TOP)/src/vtab.c \
|
||||
$(TOP)/src/wal.c \
|
||||
$(TOP)/src/wal.h \
|
||||
$(TOP)/src/walker.c \
|
||||
$(TOP)/src/where.c
|
||||
|
||||
@@ -231,6 +233,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_backup.c \
|
||||
$(TOP)/src/test_btree.c \
|
||||
$(TOP)/src/test_config.c \
|
||||
$(TOP)/src/test_demovfs.c \
|
||||
$(TOP)/src/test_devsym.c \
|
||||
$(TOP)/src/test_func.c \
|
||||
$(TOP)/src/test_hexio.c \
|
||||
@@ -246,6 +249,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_wsd.c
|
||||
|
||||
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
|
||||
@@ -254,8 +258,8 @@ TESTSRC = \
|
||||
TESTSRC2 = \
|
||||
$(TOP)/src/attach.c $(TOP)/src/backup.c $(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c $(TOP)/src/date.c \
|
||||
$(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/mem5.c \
|
||||
$(TOP)/src/os.c \
|
||||
$(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/wal.c \
|
||||
$(TOP)/src/mem5.c $(TOP)/src/os.c \
|
||||
$(TOP)/src/os_os2.c $(TOP)/src/os_unix.c $(TOP)/src/os_win.c \
|
||||
$(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c \
|
||||
$(TOP)/src/printf.c $(TOP)/src/random.c $(TOP)/src/pcache.c \
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Update\sthe\sversion\snumber\sto\s3.6.23.1.
|
||||
D 2010-03-26T22:28:06
|
||||
C Change\sthe\sxShmSize()\simplementation\sin\sos_unix.c\sso\sthat\sit\swill\sonly\nincrease\sand\snever\sdecrease\sthe\ssize\sof\sa\sshared-memory\ssegment.
|
||||
D 2010-05-13T08:33:36
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
|
||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
F Makefile.vxworks ab005d301296c40e021ccd0133ce49ca811e319f
|
||||
F Makefile.vxworks accd27bfc55cfe3aa48a58c7b9cc9c5fb225a6de
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 09d2dfb6a4a47d07b3b2091e349eedef78fb0f77
|
||||
F VERSION 4dce4379514b12d6bc5c30f7d1f64582ccb4f412
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
|
||||
@@ -22,10 +22,12 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 868fdb48c028421a203470e15c69ada15b9ba673
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 17dee87ba9b797ea22940dc0fb5b08147bfb246a
|
||||
F configure 009ceb10a7bd768b6460b7b8782eb639063c8899 x
|
||||
F configure.ac 14740970ddb674d92a9f5da89083dff1179014ff
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
|
||||
F doc/pager-invariants.txt 870107036470d7c419e93768676fae2f8749cf9e
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
|
||||
F ext/async/README.txt 0c541f418b14b415212264cbaaf51c924ec62e5b
|
||||
F ext/async/sqlite3async.c 676066c2a111a8b3107aeb59bdbbbf335c348f4a
|
||||
@@ -59,15 +61,15 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 2bb2045d1412184e9eea71eb151b159168be5131
|
||||
F ext/fts3/fts3.c 20c55bed37307a2cd590387d33a9c8127b354ab4
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h df812ef35f1b47a44ec68a44ec0c2a769c973d85
|
||||
F ext/fts3/fts3Int.h 70528ba8c33991699f96ecc64112122833cdbdb5
|
||||
F ext/fts3/fts3_expr.c f4ff02ebe854e97ac03ff00b38b728a9ab57fd4b
|
||||
F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
|
||||
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
||||
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
|
||||
F ext/fts3/fts3_porter.c 7546e4503e286a67fd4f2a82159620e3e9c7a1bc
|
||||
F ext/fts3/fts3_snippet.c 538bd27a76e465cb4ef6bfcb5479d897e4d5a536
|
||||
F ext/fts3/fts3_snippet.c bc582c38e194b48818da862f9e6f293cc44e29ee
|
||||
F ext/fts3/fts3_tokenizer.c 1a49ee3d79cbf0b9386250370d9cbfe4bb89c8ff
|
||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||
F ext/fts3/fts3_tokenizer1.c b6d86d1d750787db5c168c73da4e87670ed890a1
|
||||
@@ -77,9 +79,9 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
|
||||
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c a354f6be11a91706680936fdf77b4588f0b34dbe
|
||||
F ext/rtree/rtree.c c7a18311f2d6ae9a42838e9c04b9e670483b4feb
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test f72885ed80a329d6bd7991043016d74b51edf2c5
|
||||
F ext/rtree/rtree1.test 51bb0cd0405970501e63258401ae5ad235a4f468
|
||||
F ext/rtree/rtree2.test 7b665c44d25e51b3098068d983a39902b2e2d7a1
|
||||
F ext/rtree/rtree3.test dece988c363368af8c11862995c762071894918f
|
||||
F ext/rtree/rtree4.test 94fdd570ab5bc47244d87d4590023be43ac786bd
|
||||
@@ -90,98 +92,98 @@ F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/tkt3363.test 2bf324f7908084a5f463de3109db9c6e607feb1b
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk a36a05a481afcc00388c4d6d4db0e12cacb546e3
|
||||
F main.mk b39182f15fd980b86aceb7e4b9a1ba88abd75e2d
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
F mkopcodec.awk 3fb9bf077053c968451f4dd03d11661ac373f9d1
|
||||
F mkopcodeh.awk 29b84656502eee5f444c3147f331ee686956ab0e
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F publish.sh c74b6c2b6b63435aa1b4b43b1396dfebfae84095
|
||||
F publish.sh 313c5b2425f2cf5e547db7549a9796acc4508f22
|
||||
F publish_osx.sh 2ad2ee7d50632dff99949edc9c162dbb052f7534
|
||||
F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c e6f4d11b1c0b23642fc46bac9abe0753c4294e05
|
||||
F src/analyze.c 92a65a5a402898a52b03695c7f0cd383724d711f
|
||||
F src/attach.c 7abe1607c2054585377cdba3c219e8572f84ca5e
|
||||
F src/alter.c a9ff6f14b3935502537e90194b66c7bc79bed317
|
||||
F src/analyze.c 8dfd781ac326496746ecdfc3e099250ed5d79be5
|
||||
F src/attach.c 7f1f760bacd9c5b6cbf6fbc3ceb159ed19ee910a
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c b293534bc2df23c57668a585b17ee7faaaef0939
|
||||
F src/backup.c de9809091b3b99f69e37261c133f7f8b19f6eca6
|
||||
F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c 0d6e44d664b1775b269ea7e6f66fdffcfc32ceb3
|
||||
F src/btree.h 0e193b7e90f1d78b79c79474040e3d66a553a4fa
|
||||
F src/btreeInt.h 71ed5e7f009caf17b7dc304350b3cb64b5970135
|
||||
F src/btree.c d0414a5f09b0cacb64bd60b91c5a3720585925aa
|
||||
F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
|
||||
F src/btreeInt.h b0c87f6725b06a0aa194a6d25d54b16ce9d6e291
|
||||
F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7
|
||||
F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
|
||||
F src/callback.c 01843bdf4b0420fd28046525d150fcd9802931a9
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c ceb247eb31620bba66a94c3f697db489a1652353
|
||||
F src/date.c 485a4409a384310e6d93fd1104a9d0a8658becd9
|
||||
F src/ctime.c 51553a859994d01d8bf3500747f66a890c459774
|
||||
F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
|
||||
F src/delete.c 610dc008e88a9599f905f5cbe9577ac9c36e0581
|
||||
F src/expr.c 6baed2a0448d494233d9c0a610eea018ab386a32
|
||||
F src/expr.c 110e5eddc8c2b02f2d1b4a5afccf0ff9f7b69ef1
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
|
||||
F src/func.c 5dca069d98eca0ff70c9a8fb8ab9e1d6467187b5
|
||||
F src/func.c 0c28599430856631216b6c0131c51c89bf516026
|
||||
F src/global.c 5a9c1e3c93213ca574786ac1caa976ce8f709105
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 76d6b44a9f9050134fd81205f4b792cbdac7c925
|
||||
F src/insert.c 3a9567687f6b84ab9a41448e3d2ce20424f4743c
|
||||
F src/journal.c b0ea6b70b532961118ab70301c00a33089f9315c
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
|
||||
F src/main.c 7d89bb6dcc6993a8d32f4f22dae3e57c50a41399
|
||||
F src/malloc.c 5fa175797f982b178eaf38afba9c588a866be729
|
||||
F src/main.c cc62a14dd4a4e4f95ea21e762c87da14fe72e63c
|
||||
F src/malloc.c a08f16d134f0bfab6b20c3cd142ebf3e58235a6a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
|
||||
F src/mem2.c ee752297650632935218dcf3b20c5ed5899cb4b5
|
||||
F src/mem2.c 2ee7bdacda8299b5a91cff9f7ee3e46573195c38
|
||||
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
|
||||
F src/mem5.c eb7a5cb98915dd7a086fa415ce3a5a0f20d0acff
|
||||
F src/memjournal.c 5bfc2f33c914946e2f77ed3f882aff14dfc9355d
|
||||
F src/mutex.c 581a272e09098040ca3ef543cb5f3d643eff7d50
|
||||
F src/memjournal.c f3be374af30588de297dcf678925b2a4758e4135
|
||||
F src/mutex.c e2358d8f9a9021ab0bba4d511bb701e471e6e5f6
|
||||
F src/mutex.h 6fde601e55fa6c3fae768783c439797ab84c87c6
|
||||
F src/mutex_noop.c 5f58eaa31f2d742cb8957a747f7887ae98f16053
|
||||
F src/mutex_noop.c 10ae943d26ba86ea92319f72adbb501a89c563e0
|
||||
F src/mutex_os2.c 20477db50cf3817c2f1cd3eb61e5c177e50231db
|
||||
F src/mutex_unix.c 04a25238abce7e3d06b358dcf706e26624270809
|
||||
F src/mutex_w32.c 4cc201c1bfd11d1562810554ff5500e735559d7e
|
||||
F src/notify.c f799bbda67ab6619b36b0a24153b49518874a203
|
||||
F src/os.c 8bc63cf91e9802e2b807198e54e50227fa889306
|
||||
F src/os.h 534b082c3cb349ad05fa6fa0b06087e022af282c
|
||||
F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
|
||||
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
|
||||
F src/os_unix.c 148d2f625db3727250c0b880481ae7630b6d0eb0
|
||||
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
|
||||
F src/pager.c 1915e3ec1a2157d0c29086b7fc0c936a2d97029e
|
||||
F src/pager.h 1b32faf2e578ac3e7bcf9c9d11217128261c5c54
|
||||
F src/notify.c cbfa66a836da3a51567209636e6a94059c137930
|
||||
F src/os.c c0a5dfce2a214dacb679425632d04f8a2021f364
|
||||
F src/os.h 8a7e2456237ecf3a2e55b02f9fe6091f1ad36902
|
||||
F src/os_common.h 0d6ee583b6ee3185eb9d951f890c6dd03021a08d
|
||||
F src/os_os2.c 8ad77a418630d7dee91d1bb04f79c2096301d3a0
|
||||
F src/os_unix.c a65eb0c527306fbf8d5818c068cccb4179e2c187
|
||||
F src/os_win.c a8fc01d8483be472e495793c01064fd87e56a5c1
|
||||
F src/pager.c 1e163a82ae8405433dca559831caa06aafbba3b0
|
||||
F src/pager.h 76466c3a5af56943537f68b1f16567101a0cd1d0
|
||||
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||
F src/pcache.c 4956b41d6ba913f7a8a56fbf32be78caed0e45c2
|
||||
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 2bb2261190b42a348038f5b1c285c8cef415fcc8
|
||||
F src/pragma.c 56d95f76154a5f873c32eae485bb625f3c70be46
|
||||
F src/prepare.c 18292e5f365655cd5c5693e09508e90668f7d547
|
||||
F src/pcache1.c 6dc1871ce8ead9187161c370a58cd06c84221f76
|
||||
F src/pragma.c 423865323a4074f1e0d4ab02af0be014653e8863
|
||||
F src/prepare.c fd1398cb1da54385ba5bd68d93928f10d10a1d9c
|
||||
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c a1648d98e869937b29f4f697461fe4d60f220a7b
|
||||
F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 4113ef360430ed4e7533690ef46d06c20204adce
|
||||
F src/shell.c c40427c7245535a04a9cb4a417b6cc05c022e6a4
|
||||
F src/sqlite.h.in 08a2d9a278ff0dfd65055a7ec9c599f7ae1a3c18
|
||||
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
|
||||
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
|
||||
F src/sqlite.h.in a86bb87f5c9e97ed286a70d515d6c19de031f382
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h 6873f7f4c24fcdceece8777f2a1cbec049df77a0
|
||||
F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
|
||||
F src/status.c d329385a2cba3ea49d9d68af0ad84b22d46b4f40
|
||||
F src/sqliteInt.h 9819b45610abeca390176243a9a31758c1f0ac7a
|
||||
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
|
||||
F src/status.c 4df6fe7dce2d256130b905847c6c60055882bdbe
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c bad6570a005b234ea670b9f7b48256da19a032d3
|
||||
F src/test1.c aa9b1e10e834330e7759afb639420117e2422ded
|
||||
F src/test2.c b6b43413d495addd039a88b87d65c839f86b18cb
|
||||
F src/tclsqlite.c 6bc5fbde634b9cb42b3d29d674fa6cd0c22c0881
|
||||
F src/test1.c ff95ca772d1df51618f9f1ef7ea432cdf851f97b
|
||||
F src/test2.c 31f1b9d076b4774a22d2605d0af1f34e14a9a7bd
|
||||
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
|
||||
F src/test4.c ad03bb987ddedce928f4258c1e7fa4109a73497d
|
||||
F src/test5.c cc55900118fa4add8ec9cf69fc4225a4662f76b1
|
||||
F src/test6.c a8ece4284d0e34477f349ac05655db73c48e0926
|
||||
F src/test6.c d00c3930e2d22a9dc84415b1a2ead2ca4ab430ae
|
||||
F src/test7.c 3f2d63e4ccf97f8c2cf1a7fa0a3c8e2e2a354e6e
|
||||
F src/test8.c f959db9a22d882013b64c92753fa793b2ce3bdea
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
@@ -189,47 +191,51 @@ F src/test_async.c c1656facbaf43cb2e71b62621e5b9eb080e2621c
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
|
||||
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
|
||||
F src/test_config.c 5844274bf6cec4af3e6461fb3e2d349082635e81
|
||||
F src/test_devsym.c de3c9af2bb9a8b1e44525c449e4ec3f88e3d4110
|
||||
F src/test_config.c 6210f501d358bde619ae761f06f123529c6ba24f
|
||||
F src/test_demovfs.c da81a5f7785bb352bda7911c332a983ec4f17f27
|
||||
F src/test_devsym.c 136869028132c3dc34fe920a9fda716f391227f4
|
||||
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
|
||||
F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2
|
||||
F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
|
||||
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
|
||||
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
|
||||
F src/test_journal.c adc0ce3840ed19b49feb1d583b2212f560ef7866
|
||||
F src/test_journal.c 51da4dd6118ee843349592fde29429fab84a6243
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c f777d15df756bea0e98271932464ac5d882e66fe
|
||||
F src/test_malloc.c 2842c922b8e8d992aba722214952204ca025b411
|
||||
F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
|
||||
F src/test_onefile.c 06da7e085dce42924cf062b91763dd4bb84c6101
|
||||
F src/test_osinst.c 90fb03d396f39956897dfb4bd0e62c6711db1cca
|
||||
F src/test_onefile.c df4d7858b5cd1dffe92d36ec9dbad11f0037ffd1
|
||||
F src/test_osinst.c f5d1a4ee8b80fc58d1430c56146de748584013a9
|
||||
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 00fed80690ae7f1525483a35861511c48bc579f2
|
||||
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
|
||||
F src/test_vfs.c 3601f9b6d46cb6daf0697d60c76bf8e18b90b123
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||
F src/trigger.c 340c9eca0fb24b1197468d96ba059f867c9834c7
|
||||
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
||||
F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||
F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee
|
||||
F src/vdbe.c 8acca6dab2505e9650f6f014ada6ef30570cba99
|
||||
F src/vacuum.c b17355fc10cef0875626932ec2f1fa1deb0daa48
|
||||
F src/vdbe.c 8c6301a7dd844d2d6370ebd46f4e2d0cf449c2de
|
||||
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
|
||||
F src/vdbeInt.h ae1e6ba0dd3fb4a886898d2829d748be701b01f8
|
||||
F src/vdbeapi.c 74c25680046a116b24b95393914d3669c23305dc
|
||||
F src/vdbeaux.c 0f352f63be78138bd94275aa3c8361e760ecc639
|
||||
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
|
||||
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
|
||||
F src/vdbeaux.c 69f5887979504b464b8dda565816541adab3e2df
|
||||
F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c 606adf51cd6d4ba51a8c6dccede06a6f7b0dd72d
|
||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||
F src/wal.c 3806c5ed7047debc408665b3576f17bab05b2be6
|
||||
F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 399ea4c090284c9d16f76d685b9b44e8b9b4442b
|
||||
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
||||
F test/alter.test 645b2e8d23c9936f9494af9d2fa7f8351a248c6e
|
||||
F test/alter2.test d0133bfa7a0a24aa84c034051410b95217d24a35
|
||||
F test/alter.test 15f9224868b290d6bf7a63f31437f31aee070636
|
||||
F test/alter2.test 0266160d61b0f7156b7e7a9905dbf85ebe067c63
|
||||
F test/alter3.test 25b95a136708f22b87184fa6a4309eea03d65153
|
||||
F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
@@ -239,7 +245,7 @@ F test/analyze3.test 506203875258ffd8ffa879b9c3c5432022d2b6d8
|
||||
F test/async.test 8c75d31b8330f8b70cf2571b014d4476a063efdb
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
F test/async4.test aafa6328c559d3e4bb587de770cbdecfca06f0da
|
||||
F test/async4.test 166cc07057ff6f908fe42dcffaa8ca732c757acb
|
||||
F test/async5.test f3592d79c84d6e83a5f50d3fd500445f7d97dfdf
|
||||
F test/attach.test ce9660e51768fab93cf129787be886c5d6c4fd81
|
||||
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
||||
@@ -249,16 +255,17 @@ F test/auth.test 8f21c160a4562f54f27618e85bac869efcecbcaf
|
||||
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46
|
||||
F test/autoindex1.test ffb06a246e2c1f89cfbe3d93eca513c9e78d4063
|
||||
F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
|
||||
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
|
||||
F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
|
||||
F test/backup.test 3549ea8f541a08205c0eb813b21e81ea8301f6ed
|
||||
F test/avtrans.test 7a26ffc6a355b7fbff2a082f56180ede863b126c
|
||||
F test/backup.test 5f7f66d067e695a6040be3295a5abc289f823838
|
||||
F test/backup2.test 159419073d9769fdb1780ed7e5b391a046f898d5
|
||||
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
|
||||
F test/backup_malloc.test 1e063c6d75143d0d6e0ae77971dd690070369387
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070
|
||||
F test/bigfile.test b746a34ce0e2039994b45fea8b7fbfa78f594cdf
|
||||
F test/bigfile.test 1e12ce56e59fc41ace231009599506c22b031fbb
|
||||
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
|
||||
F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c
|
||||
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
|
||||
@@ -274,7 +281,7 @@ F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
|
||||
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 3ff445c445742a7b6b9ba6e1d62a25263f9424b9
|
||||
F test/capi2.test 172c717ed101e78e0798dd21b9896a22366f35b4
|
||||
F test/capi2.test 00032d7504b9c14f1b36331670c5e7b0f73e3c5d
|
||||
F test/capi3.test 168e2cd66c58c510955b0f299750e4de73b8d952
|
||||
F test/capi3b.test 664eb55318132f292f2c436f90906f578cad6b97
|
||||
F test/capi3c.test 493385107dcedfaf4f2b1c3738c8c1fa00362006
|
||||
@@ -285,7 +292,7 @@ F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
|
||||
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
|
||||
F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c
|
||||
F test/collate4.test 4545554388daaa604e5b3def3aa2f7ed6d56e8da
|
||||
F test/collate4.test 3d3f123f83fd8ccda6f48d617e44e661b9870c7d
|
||||
F test/collate5.test fe0f43c4740d7b71b959cac668d19e42f2e06e4d
|
||||
F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907
|
||||
F test/collate7.test fac8db7aac3978466c04ae892cc74dcf2bc031aa
|
||||
@@ -296,7 +303,7 @@ F test/colmeta.test 087c42997754b8c648819832241daf724f813322
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 0ed68b11f22721052d880ee80bd528a0e0828236
|
||||
F test/corrupt.test 0d346c9fe064ca71281685a8a732fcc83461bb99
|
||||
F test/corrupt2.test a571e30ea4e82318f319a24b6cc55935ce862079
|
||||
F test/corrupt2.test 576122d756feda40e63ef1c1ff6c4720a927d126
|
||||
F test/corrupt3.test 263e8bb04e2728df832fddf6973cf54c91db0c32
|
||||
F test/corrupt4.test acdb01afaedf529004b70e55de1a6f5a05ae7fff
|
||||
F test/corrupt5.test c23da7bfb20917cc7fdbb13ee25c7cc4e9fffeff
|
||||
@@ -304,11 +311,11 @@ F test/corrupt6.test e69b877d478224deab7b66844566258cecacd25e
|
||||
F test/corrupt7.test 1eb2214f29474fa6b155aa3da8a7d46bf52089e1
|
||||
F test/corrupt8.test 9992ef7f67cefc576b92373f6bf5ab8775280f51
|
||||
F test/corrupt9.test 4aa1cb1ef091cb0e13e89a819c72911631b5176a
|
||||
F test/corruptA.test 99e95620b980161cb3e79f06a884a4bb8ae265ff
|
||||
F test/corruptB.test 66b4544104dd03d0f33ea69ddac3fa4a682cd3c2
|
||||
F test/corruptA.test 38b4f81c16099f6d8fa8b37e188fde76b8243994
|
||||
F test/corruptB.test d88b500f7994cb2eb9646410c263111e9831f889
|
||||
F test/corruptC.test 691ed070baef5e1345939caadf270a52837a5064
|
||||
F test/corruptD.test 3ae6e2dc6e2226c6935a8a40d4b5ee3eba75f8c0
|
||||
F test/corruptE.test dbf66cae4c0e977ca9625a9114cdd01df8967bef
|
||||
F test/corruptE.test 34de490791060d749c933aef3970839df3f63ea9
|
||||
F test/count.test 454e1ce985c94d13efeac405ce54439f49336163
|
||||
F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89
|
||||
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
|
||||
@@ -323,6 +330,7 @@ F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/ctime.test f5040beef89c1b2bdb6a9edb7358a519213ff80c
|
||||
F test/date.test 0b8473ed9ab6fd4283b4a01f035e1067762ba734
|
||||
F test/dbstatus.test 838447a0ecca1232675b025c0a518a9ef0f8057e
|
||||
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||
F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4
|
||||
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
||||
@@ -333,7 +341,7 @@ F test/descidx3.test 3394ad4d089335cac743c36a14129d6d931c316f
|
||||
F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_fkey.test 6721a741c6499b3ab7e5385923233343c8f1ad05
|
||||
F test/e_fts3.test 5adb033fae6e07002d11f4a7c8f8e8ff9f31e8ec
|
||||
F test/e_fts3.test 75bb0aee26384ef586165e21018a17f7cd843469
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
|
||||
F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
|
||||
@@ -345,7 +353,7 @@ F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
|
||||
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
|
||||
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
F test/fkey2.test e71f5baf9bb42cdba4700d73cba6f4d82fd6b925
|
||||
F test/fkey2.test d5e065ede294ab52affe2116d54dc85a09301354
|
||||
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
|
||||
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
@@ -384,7 +392,7 @@ F test/fts2q.test b2fbbe038b7a31a52a6079b215e71226d8c6a682
|
||||
F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e
|
||||
F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a
|
||||
F test/fts3.test ae0433b09b12def08105640e57693726c4949338
|
||||
F test/fts3_common.tcl 1d887ded06dac9b993cfb175618df7f70c796de2
|
||||
F test/fts3_common.tcl 4d8eec9db565fed9098f45c378f28e1657802011
|
||||
F test/fts3aa.test 5327d4c1d9b6c61021696746cc9a6cdc5bf159c0
|
||||
F test/fts3ab.test 09aeaa162aee6513d9ff336b6932211008b9d1f9
|
||||
F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63
|
||||
@@ -410,8 +418,8 @@ F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3malloc.test 059592c4f37ccd30138bbf8e3e5b7982cb5c8f2e
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
F test/fts3query.test 154fe4b015fd61af523ee083570a134f508f5be7
|
||||
F test/fts3rnd.test 2f5761db9dd92f6fe09d08976ac658ef521846ed
|
||||
F test/fts3query.test 2468caf7938dbc3be2e049524320ce4faf2227b3
|
||||
F test/fts3rnd.test 707533ce943f490443ce5e696236bb1675a37635
|
||||
F test/fts3snippet.test 9f9a4a7e396c5d8ce2898be65ebabc429555430f
|
||||
F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f
|
||||
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
|
||||
@@ -421,7 +429,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 4eca9d345f06d5b0b0105f7a2ef9e7f22658827b
|
||||
F test/hook.test c9c992f2914977072a71e98df3bfcad1f47737c9
|
||||
F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a
|
||||
F test/icu.test 1fc0ff9a3bafc80abf679b11afc0f8a3ce995abd
|
||||
F test/in.test d49419c6df515852f477fa513f3317181d46bc92
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
@@ -437,7 +445,7 @@ F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 727d55dceb9a4ec36675057bb5becfc265e28ca6
|
||||
F test/indexedby.test 946ca2628a521f4ced0520421a0788345abaf3dc
|
||||
F test/init.test 3f9e97948cf2335c08a5e3edc3df3a26cdaa76f2
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
|
||||
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
@@ -446,7 +454,7 @@ F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1
|
||||
F test/intpkey.test 537669fd535f62632ca64828e435b9e54e8d677f
|
||||
F test/io.test e7bd58edb4e2131a8ecd81b4b00af3ee5c79d464
|
||||
F test/io.test 1b895d6774491895cbc75659969f07ca01860c88
|
||||
F test/ioerr.test 390785ec65f10aa58a82b048ee12e9052d783fa8
|
||||
F test/ioerr2.test 1b56cb80d5b0726ee3ba325ca175734541e32955
|
||||
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
@@ -459,7 +467,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
|
||||
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
|
||||
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
||||
F test/jrnlmode.test a765844f22b3f6d72d78a68d5decd26c64bb859c
|
||||
F test/jrnlmode.test a7407c0f193696f0ef303c663916c89e3bc4605d
|
||||
F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd
|
||||
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
||||
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
||||
@@ -471,12 +479,13 @@ F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e
|
||||
F test/loadext.test 0393ce12d9616aa87597dd0ec88181de181f6db0
|
||||
F test/loadext2.test 0bcaeb4d81cd5b6e883fdfea3c1bdbe1f173cbca
|
||||
F test/lock.test 842e80b6be816c79525a20b098cca066989feed7
|
||||
F test/lock2.test 7bb642551df59b3de135291d62ee82409420181e
|
||||
F test/lock2.test 64ba8f1c7709abf91287d564984a6b8c5209e755
|
||||
F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00
|
||||
F test/lock4.test f4f36271aa5ae1da449646bf43c7341f6b2b4c4e
|
||||
F test/lock5.test 6b1f78f09ad1522843dad571b76b321e6f439bf7
|
||||
F test/lock6.test 862aa71e97b288d6b3f92ba3313f51bd0b003776
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lock_common.tcl bbc4e15ee5334cc4d01fcac08d7c9de7d8906e55
|
||||
F test/lookaside.test 1dd350dc6dff015c47c07fcc5a727a72fc5bae02
|
||||
F test/main.test 2be2352ac77ac5b238c6337a5469aeeef57677e6
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
@@ -500,7 +509,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
||||
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl 984baeb6c6b185e798827d1187d426acc2bc4962
|
||||
F test/malloc_common.tcl f95c4d3459877e64c2d856b8a9c39210f9968ddf
|
||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
|
||||
@@ -509,7 +518,7 @@ F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
|
||||
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
F test/minmax3.test a38686c33b07d595e98a2fc6d3aa84a5e886a972
|
||||
F test/misc1.test 1b89c02c4a33b49dee4cd1d20d161aaaba719075
|
||||
F test/misc1.test e56baf44656dd68d6475a4b44521045a60241e9b
|
||||
F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd
|
||||
F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6
|
||||
F test/misc4.test 91e8ed25c092c2bb4e0bb01864631e2930f8d7de
|
||||
@@ -529,33 +538,33 @@ F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
|
||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||
F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
|
||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||
F test/permutations.test 91928573ca2db2c88dbc50ab34e4a585d912b580
|
||||
F test/pragma.test 5aeb48a442dba3c3e8e38773b121371814ab3b17
|
||||
F test/permutations.test d5872f8d7f854e0e78d127a7e148c58b2703c8a8
|
||||
F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/quick.test d6591e74f3ac19da7fd076845f06dca48fd43cff
|
||||
F test/quick.test 6f202befe1cfae0b63df96b3120a8022ab11f574
|
||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
|
||||
F test/rdonly.test bd054831f8a3078e765a0657e247182486f0cb47
|
||||
F test/rdonly.test c243623b26c311faab2aee311a26af372e123a65
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/rollback.test 73355ad4492ff9a3a31e61c7e5eb5e01a1de94ca
|
||||
F test/rowhash.test 97f56043ba11f0679920416c0cdbc72e5272267b
|
||||
F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287
|
||||
F test/rtree.test 55466a200af3591946c5da77ad5dbfbc1e5e05f9
|
||||
F test/savepoint.test f2ede4b643ad87ead36c041c72d774a1f5c8a564
|
||||
F test/savepoint2.test 427c8b20f43d3edf17a290c6788ae9e2703ac51c
|
||||
F test/savepoint.test 14f78c2c2538764850b38446957048113cc24f75
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
F test/savepoint6.test 2df1d093e59e78d688c64eb20e0457aaea7d08f9
|
||||
F test/savepoint6.test bdc653c5c08328c84a74471b5b23fd483b919dfe
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/securedel.test 328d2921c0ca49bdd3352e516b0377fc07143254
|
||||
F test/select1.test f67ca2dfc05df41c7b86eb32ca409b427a5f43b0
|
||||
F test/select2.test 9735da20ccd41e42bf2b4c19fd939141b591adae
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 44aa6e7110592e18110b0b9cf5c024d37d23be17
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
@@ -565,7 +574,7 @@ F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test b4007b15396cb7ba2615cab31e1973b572e43210
|
||||
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
||||
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
||||
F test/selectC.test 07a45610c8b3bd878943004fd23f4cc0682bd4c0
|
||||
F test/selectC.test 33bb5673a8141df193c6fd56e6de7fea38b8d2ee
|
||||
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
||||
F test/shared.test 3b448dc0f7a9356e641894ed81c27599f39d809d
|
||||
F test/shared2.test d6ba4ca1827ea36a1ac23a99e3c36eeac9165450
|
||||
@@ -594,13 +603,13 @@ F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
|
||||
F test/table.test bf102a5669c4db7a41330802f24a4a81a4204f83
|
||||
F test/table.test 04ba066432430657712d167ebf28080fe878d305
|
||||
F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516
|
||||
F test/tclsqlite.test bf4227eb236a4c097aa7974a2bf7d3225acf34be
|
||||
F test/tclsqlite.test 013133fa83128569c6fb8a7a48dc7c4507e6ff1c
|
||||
F test/tempdb.test 1bf52da28a9c24e29717362a87722dff08feb72b
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||
F test/tester.tcl e1f581c7a2648a0aaa51135c4d2e7be68f4b9292
|
||||
F test/tester.tcl f6b79073ad3a18439ad3a643f812e1d0c47dbb7b
|
||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||
@@ -608,9 +617,11 @@ F test/thread004.test f51dfc3936184aaf73ee85f315224baad272a87f
|
||||
F test/thread005.test bf5c374ca65dd89fd56c8fe511ccfb46875bda5e
|
||||
F test/thread1.test 862dd006d189e8b0946935db17399dcac2f8ef91
|
||||
F test/thread2.test 6e0997f7beabb6a7e471bd18740ed04805c785f4
|
||||
F test/thread_common.tcl b65e6b1d1d90dc885e10ad080896c6c56eef0819
|
||||
F test/thread_common.tcl 0b07423d29ddb73d4bacbac69268c8d37b6cc5d2
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9
|
||||
F test/tkt-02a8e81d44.test 58494de77be2cf249228ada3f313fa399821c6ab
|
||||
F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660
|
||||
F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
|
||||
F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e
|
||||
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
|
||||
@@ -618,6 +629,8 @@ F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
|
||||
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
|
||||
F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527
|
||||
F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f
|
||||
F test/tkt-9d68c883.test 4251ef9fa08158e50b28a682e56124457a59d048
|
||||
F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589
|
||||
F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6
|
||||
F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87
|
||||
F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00
|
||||
@@ -706,7 +719,7 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
|
||||
F test/trans.test d887cb07630dc39879a322d958ad8b006137485c
|
||||
F test/trans.test f19bd2c8b5ccc89295454a42b35319b1381b9a3d
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
|
||||
F test/trigger1.test 2e18561f85e448bb633c9c9de792e9bbf7b2dd3e
|
||||
@@ -718,9 +731,9 @@ F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
||||
F test/trigger7.test 72feaf8dbc52cea84de0c3e6ce7559ff19c479af
|
||||
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
||||
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
|
||||
F test/triggerA.test 0718ad2d9bfef27c7af00e636df79bee6b988da7
|
||||
F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test 4083c64d80854d271bad211268a08985f3d61cbd
|
||||
F test/triggerC.test cac41fe31adc1abb9fa08532762fc2b4f662ab03
|
||||
F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7
|
||||
F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
@@ -728,7 +741,7 @@ F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
|
||||
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
|
||||
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test 68e39b2228b4b772166debef4a82accf6ddd32f3
|
||||
F test/vacuum.test 15ae6784e70428b8db64e95c92d84b19e507b719
|
||||
F test/vacuum2.test ec57f21d394b7b72249b11f8e4b5d487bab56539
|
||||
F test/vacuum3.test f39ad1428347c5808cd2da7578c470f186a4d0ce
|
||||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
@@ -752,14 +765,23 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test 7a100918c45872fa19cfb4413299b9afb08727b6
|
||||
F test/wal2.test 2eba114ff58f0688278ad45249625af89a0bc9fa
|
||||
F test/walbak.test a0e45187c7d8928df035dfea29b99b016b21ca3c
|
||||
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
|
||||
F test/walfault.test 98df47444944a6db2161eed5cef71d6c00bcb8c3
|
||||
F test/walhook.test c3314e30baf074dd087d52d21ea6f1d09138b0a0
|
||||
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
F test/walthread.test 1a8c55cd9e3272ba0caa028d8f0ead04989a3378
|
||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||
F test/where2.test 45eacc126aabb37959a387aa83e59ce1f1f03820
|
||||
F test/where3.test 97d3936e6a443b968f1a61cdcc0f673252000e94
|
||||
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
|
||||
F test/where3.test aa44a9b29e8c9f3d7bb94a3bb3a95b31627d520d
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test fdd58ab9dec9f97679e65d4414bf5e07d725d79f
|
||||
F test/where8.test 2bb8ea44b745fcc93db150fac9ce33d12e499760
|
||||
F test/where7.test a0a92b8ce48d9c027fbdd7b764c7de1e1213575a
|
||||
F test/where8.test a6c740fd286d7883e274e17b6230a9d672a7ab1f
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test be19e1a92f80985c1a121b4678bf7d2123eaa623
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
@@ -775,7 +797,7 @@ F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c.tcl 4c6924c7e877defa8f9a12ef1e6867de614acf3f
|
||||
F tool/mksqlite3c.tcl aff0d53f0e84cf919922c0d02e767bdf5eeafb90
|
||||
F tool/mksqlite3h.tcl eb100dce83f24b501b325b340f8b5eb8e5106b3b
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
|
||||
@@ -784,7 +806,7 @@ F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/shell1.test ef08a3e738b9fee4fc228920956950bc35db0575
|
||||
F tool/shell2.test 8f51f61c13b88618e71c17439fe0847c2421c5d1
|
||||
F tool/shell3.test ff663e83100670a295d473515c12beb8103a78b6
|
||||
F tool/showdb.c 8ab8b3b53884312aafb7ef60982e255a6c31d238
|
||||
F tool/showdb.c 12fbece85695e3a61bdb4f7607b61f264120c4b6
|
||||
F tool/showjournal.c ec3b171be148656827c4949fbfb8ab4370822f87
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
|
||||
@@ -795,14 +817,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P b1f342a6643829020beef542a0700d90822e6467
|
||||
R 590a011d9441875bded2c173c371f1c1
|
||||
P 3cab9022457ce50f82c5822d8ba6c04a3a85cb6a
|
||||
R 8a7d44076bf0e05c11800be3998eddd6
|
||||
U drh
|
||||
Z f7171db765620a4ccff85bc2ced22202
|
||||
Z 3a36caf9fe5b6632b303e603e184218b
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFLrTT6oxKgR168RlERArP2AJ0UeA3bKxomgH1prR7M+4tHuMlN7wCfXBZE
|
||||
Jr7IGDFSJ/vsM6VpeiKkkf4=
|
||||
=diSA
|
||||
iD8DBQFL67ljoxKgR168RlERAvKRAJ9jAZ2qvV6Q9GpsBE6wLhS3nq7pbACfcnYP
|
||||
hXJABDPCTP9dztwWLTfVSAc=
|
||||
=rTx0
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
b078b588d617e07886ad156e9f54ade6d823568e
|
||||
149d2ae4a6fe2f86822f286d2a7092c51bec7ebb
|
||||
+14
-13
@@ -34,19 +34,6 @@ gzip sqlite3-$VERS.bin
|
||||
chmod 644 sqlite3-$VERS.bin.gz
|
||||
mv sqlite3-$VERS.bin.gz doc
|
||||
|
||||
# Build a source archive useful for windows.
|
||||
#
|
||||
make target_source
|
||||
cd tsrc
|
||||
echo '***** BUILDING preprocessed source archives'
|
||||
rm fts[12]* icu*
|
||||
rm -f ../doc/sqlite-source-$VERSW.zip
|
||||
zip ../doc/sqlite-source-$VERSW.zip *
|
||||
cd ..
|
||||
cp tsrc/sqlite3.h tsrc/sqlite3ext.h .
|
||||
pwd
|
||||
zip doc/sqlite-amalgamation-$VERSW.zip sqlite3.c sqlite3.h sqlite3ext.h
|
||||
|
||||
# Build the sqlite.so and tclsqlite.so shared libraries
|
||||
# under Linux
|
||||
#
|
||||
@@ -87,6 +74,20 @@ i386-mingw32msvc-gcc -Os $OPTS -Itsrc -I$TCLDIR sqlite3.c tsrc/shell.c \
|
||||
-o sqlite3.exe
|
||||
zip doc/sqlite-$VERSW.zip sqlite3.exe
|
||||
|
||||
# Build a source archive useful for windows.
|
||||
#
|
||||
make target_source
|
||||
cd tsrc
|
||||
echo '***** BUILDING preprocessed source archives'
|
||||
rm fts[12]* icu*
|
||||
rm -f ../doc/sqlite-source-$VERSW.zip
|
||||
zip ../doc/sqlite-source-$VERSW.zip *
|
||||
cd ..
|
||||
cp tsrc/sqlite3.h tsrc/sqlite3ext.h .
|
||||
cp tsrc/shell.c .
|
||||
pwd
|
||||
zip doc/sqlite-amalgamation-$VERSW.zip sqlite3.c sqlite3.h sqlite3ext.h shell.c sqlite3.def
|
||||
|
||||
# Construct a tarball of the source tree
|
||||
#
|
||||
echo '***** BUILDING source archive'
|
||||
|
||||
+21
-8
@@ -226,17 +226,23 @@ static void renameTriggerFunc(
|
||||
/*
|
||||
** Register built-in functions used to help implement ALTER TABLE
|
||||
*/
|
||||
void sqlite3AlterFunctions(sqlite3 *db){
|
||||
sqlite3CreateFunc(db, "sqlite_rename_table", 2, SQLITE_UTF8, 0,
|
||||
renameTableFunc, 0, 0);
|
||||
void sqlite3AlterFunctions(void){
|
||||
static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
|
||||
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0,
|
||||
renameTriggerFunc, 0, 0);
|
||||
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
sqlite3CreateFunc(db, "sqlite_rename_parent", 3, SQLITE_UTF8, 0,
|
||||
renameParentFunc, 0, 0);
|
||||
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
|
||||
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
|
||||
|
||||
for(i=0; i<ArraySize(aAlterTableFuncs); i++){
|
||||
sqlite3FuncDefInsert(pHash, &aFunc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -380,7 +386,9 @@ void sqlite3AlterRenameTable(
|
||||
char *zWhere = 0; /* Where clause to locate temp triggers */
|
||||
#endif
|
||||
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
|
||||
|
||||
int savedDbFlags; /* Saved value of db->flags */
|
||||
|
||||
savedDbFlags = db->flags;
|
||||
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
|
||||
assert( pSrc->nSrc==1 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
||||
@@ -389,6 +397,7 @@ void sqlite3AlterRenameTable(
|
||||
if( !pTab ) goto exit_rename_table;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
zDb = db->aDb[iDb].zName;
|
||||
db->flags |= SQLITE_PreferBuiltin;
|
||||
|
||||
/* Get a NULL terminated version of the new table name. */
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
@@ -556,6 +565,7 @@ void sqlite3AlterRenameTable(
|
||||
exit_rename_table:
|
||||
sqlite3SrcListDelete(db, pSrc);
|
||||
sqlite3DbFree(db, zName);
|
||||
db->flags = savedDbFlags;
|
||||
}
|
||||
|
||||
|
||||
@@ -675,9 +685,11 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
|
||||
if( zCol ){
|
||||
char *zEnd = &zCol[pColDef->n-1];
|
||||
int savedDbFlags = db->flags;
|
||||
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
|
||||
*zEnd-- = '\0';
|
||||
}
|
||||
db->flags |= SQLITE_PreferBuiltin;
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\".%s SET "
|
||||
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
|
||||
@@ -686,6 +698,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
zTab
|
||||
);
|
||||
sqlite3DbFree(db, zCol);
|
||||
db->flags = savedDbFlags;
|
||||
}
|
||||
|
||||
/* If the default value of the new column is NULL, then set the file
|
||||
|
||||
+9
-5
@@ -618,12 +618,16 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
n = 24;
|
||||
}
|
||||
pSample->nByte = (u8)n;
|
||||
pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
|
||||
if( pSample->u.z ){
|
||||
memcpy(pSample->u.z, z, n);
|
||||
if( n < 1){
|
||||
pSample->u.z = 0;
|
||||
}else{
|
||||
db->mallocFailed = 1;
|
||||
break;
|
||||
pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
|
||||
if( pSample->u.z ){
|
||||
memcpy(pSample->u.z, z, n);
|
||||
}else{
|
||||
db->mallocFailed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -143,7 +143,8 @@ static void attachFunc(
|
||||
}
|
||||
pPager = sqlite3BtreePager(aNew->pBt);
|
||||
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
|
||||
sqlite3PagerJournalMode(pPager, db->dfltJournalMode);
|
||||
/* journal_mode set by the OP_JournalMode opcode that will following
|
||||
** the OP_Function opcode that invoked this function. */
|
||||
sqlite3BtreeSecureDelete(aNew->pBt,
|
||||
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
|
||||
}
|
||||
@@ -339,6 +340,17 @@ static void codeAttach(
|
||||
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
|
||||
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
|
||||
|
||||
if( type==SQLITE_ATTACH ){
|
||||
/* On an attach, also set the journal mode. Note that
|
||||
** sqlite3VdbeUsesBtree() is not call here since the iDb index
|
||||
** will be out of range prior to the new database being attached.
|
||||
** The OP_JournalMode opcode will all sqlite3VdbeUsesBtree() for us.
|
||||
*/
|
||||
sqlite3VdbeAddOp3(v, OP_JournalMode, db->nDb, regArgs+3,
|
||||
db->dfltJournalMode);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
}
|
||||
|
||||
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
|
||||
** statement only). For DETACH, set it to false (expire all existing
|
||||
** statements).
|
||||
|
||||
+30
-18
@@ -217,7 +217,7 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
|
||||
/* Catch the case where the destination is an in-memory database and the
|
||||
** page sizes of the source and destination differ.
|
||||
*/
|
||||
if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){
|
||||
if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
@@ -287,6 +287,9 @@ static void attachBackupObject(sqlite3_backup *p){
|
||||
*/
|
||||
int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
int rc;
|
||||
int destMode; /* Destination journal mode */
|
||||
int pgszSrc = 0; /* Source page size */
|
||||
int pgszDest = 0; /* Destination page size */
|
||||
|
||||
sqlite3_mutex_enter(p->pSrcDb->mutex);
|
||||
sqlite3BtreeEnter(p->pSrc);
|
||||
@@ -327,13 +330,22 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
rc = sqlite3BtreeBeginTrans(p->pSrc, 0);
|
||||
bCloseTrans = 1;
|
||||
}
|
||||
|
||||
/* Do not allow backup if the destination database is in WAL mode
|
||||
** and the page sizes are different between source and destination */
|
||||
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
|
||||
pgszDest = sqlite3BtreeGetPageSize(p->pDest);
|
||||
destMode = sqlite3PagerJournalMode(sqlite3BtreePager(p->pDest),
|
||||
PAGER_JOURNALMODE_QUERY);
|
||||
if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
/* Now that there is a read-lock on the source database, query the
|
||||
** source pager for the number of pages in the database.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerPagecount(pSrcPager, &nSrcPage);
|
||||
}
|
||||
nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc);
|
||||
assert( nSrcPage>=0 );
|
||||
for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){
|
||||
const Pgno iSrcPg = p->iNext; /* Source page number */
|
||||
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
|
||||
@@ -364,8 +376,6 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
if( rc==SQLITE_DONE
|
||||
&& (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
|
||||
){
|
||||
const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
|
||||
const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
|
||||
int nDestTruncate;
|
||||
|
||||
if( p->pDestDb ){
|
||||
@@ -384,18 +394,20 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
** journalled by PagerCommitPhaseOne() before they are destroyed
|
||||
** by the file truncation.
|
||||
*/
|
||||
if( nSrcPagesize<nDestPagesize ){
|
||||
int ratio = nDestPagesize/nSrcPagesize;
|
||||
assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
|
||||
assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
|
||||
if( pgszSrc<pgszDest ){
|
||||
int ratio = pgszDest/pgszSrc;
|
||||
nDestTruncate = (nSrcPage+ratio-1)/ratio;
|
||||
if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
|
||||
nDestTruncate--;
|
||||
}
|
||||
}else{
|
||||
nDestTruncate = nSrcPage * (nSrcPagesize/nDestPagesize);
|
||||
nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
|
||||
}
|
||||
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
|
||||
|
||||
if( nSrcPagesize<nDestPagesize ){
|
||||
if( pgszSrc<pgszDest ){
|
||||
/* If the source page-size is smaller than the destination page-size,
|
||||
** two extra things may need to happen:
|
||||
**
|
||||
@@ -405,31 +417,31 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
** pending-byte page in the source database may need to be
|
||||
** copied into the destination database.
|
||||
*/
|
||||
const i64 iSize = (i64)nSrcPagesize * (i64)nSrcPage;
|
||||
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
|
||||
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
|
||||
|
||||
assert( pFile );
|
||||
assert( (i64)nDestTruncate*(i64)nDestPagesize >= iSize || (
|
||||
assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
|
||||
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
|
||||
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+nDestPagesize
|
||||
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
|
||||
));
|
||||
if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
|
||||
&& SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
|
||||
&& SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
|
||||
){
|
||||
i64 iOff;
|
||||
i64 iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
|
||||
i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
|
||||
for(
|
||||
iOff=PENDING_BYTE+nSrcPagesize;
|
||||
iOff=PENDING_BYTE+pgszSrc;
|
||||
rc==SQLITE_OK && iOff<iEnd;
|
||||
iOff+=nSrcPagesize
|
||||
iOff+=pgszSrc
|
||||
){
|
||||
PgHdr *pSrcPg = 0;
|
||||
const Pgno iSrcPg = (Pgno)((iOff/nSrcPagesize)+1);
|
||||
const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
|
||||
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *zData = sqlite3PagerGetData(pSrcPg);
|
||||
rc = sqlite3OsWrite(pFile, zData, nSrcPagesize, iOff);
|
||||
rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
|
||||
}
|
||||
sqlite3PagerUnref(pSrcPg);
|
||||
}
|
||||
|
||||
+154
-68
@@ -516,11 +516,8 @@ static void invalidateIncrblobCursors(
|
||||
static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
|
||||
int rc = SQLITE_OK;
|
||||
if( !pBt->pHasContent ){
|
||||
int nPage = 100;
|
||||
sqlite3PagerPagecount(pBt->pPager, &nPage);
|
||||
/* If sqlite3PagerPagecount() fails there is no harm because the
|
||||
** nPage variable is unchanged from its default value of 100 */
|
||||
pBt->pHasContent = sqlite3BitvecCreate((u32)nPage);
|
||||
assert( pgno<=pBt->nPage );
|
||||
pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
|
||||
if( !pBt->pHasContent ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -1563,13 +1560,13 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
|
||||
** Return the size of the database file in pages. If there is any kind of
|
||||
** error, return ((unsigned int)-1).
|
||||
*/
|
||||
static Pgno pagerPagecount(BtShared *pBt){
|
||||
int nPage = -1;
|
||||
int rc;
|
||||
assert( pBt->pPage1 );
|
||||
rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
|
||||
assert( rc==SQLITE_OK || nPage==-1 );
|
||||
return (Pgno)nPage;
|
||||
static Pgno btreePagecount(BtShared *pBt){
|
||||
return pBt->nPage;
|
||||
}
|
||||
u32 sqlite3BtreeLastPage(Btree *p){
|
||||
assert( sqlite3BtreeHoldsMutex(p) );
|
||||
assert( ((p->pBt->nPage)&0x8000000)==0 );
|
||||
return (int)btreePagecount(p->pBt);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1586,9 +1583,11 @@ static int getAndInitPage(
|
||||
MemPage **ppPage /* Write the page pointer here */
|
||||
){
|
||||
int rc;
|
||||
TESTONLY( Pgno iLastPg = pagerPagecount(pBt); )
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
|
||||
if( pgno<=0 || pgno>btreePagecount(pBt) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = btreeGetPage(pBt, pgno, ppPage, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = btreeInitPage(*ppPage);
|
||||
@@ -1596,15 +1595,6 @@ static int getAndInitPage(
|
||||
releasePage(*ppPage);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the requested page number was either 0 or greater than the page
|
||||
** number of the last page in the database, this function should return
|
||||
** SQLITE_CORRUPT or some other error (i.e. SQLITE_FULL). Check that this
|
||||
** is the case. */
|
||||
assert( (pgno>0 && pgno<=iLastPg) || rc!=SQLITE_OK );
|
||||
testcase( pgno==0 );
|
||||
testcase( pgno==iLastPg );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2240,9 +2230,11 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){
|
||||
** is returned if we run out of memory.
|
||||
*/
|
||||
static int lockBtree(BtShared *pBt){
|
||||
int rc;
|
||||
MemPage *pPage1;
|
||||
int nPage;
|
||||
int rc; /* Result code from subfunctions */
|
||||
MemPage *pPage1; /* Page 1 of the database file */
|
||||
int nPage; /* Number of pages in the database */
|
||||
int nPageFile = 0; /* Number of pages in the database file */
|
||||
int nPageHeader; /* Number of pages in the database according to hdr */
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( pBt->pPage1==0 );
|
||||
@@ -2254,10 +2246,14 @@ static int lockBtree(BtShared *pBt){
|
||||
/* Do some checking to help insure the file we opened really is
|
||||
** a valid database file.
|
||||
*/
|
||||
rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
|
||||
if( (rc = sqlite3PagerPagecount(pBt->pPager, &nPageFile))!=SQLITE_OK ){;
|
||||
goto page1_init_failed;
|
||||
}else if( nPage>0 ){
|
||||
}
|
||||
if( nPage==0 ){
|
||||
nPage = nPageFile;
|
||||
}
|
||||
if( nPage>0 ){
|
||||
int pageSize;
|
||||
int usableSize;
|
||||
u8 *page1 = pPage1->aData;
|
||||
@@ -2265,12 +2261,42 @@ static int lockBtree(BtShared *pBt){
|
||||
if( memcmp(page1, zMagicHeader, 16)!=0 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
if( page1[18]>1 ){
|
||||
pBt->readOnly = 1;
|
||||
}
|
||||
if( page1[19]>1 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
#else
|
||||
if( page1[18]>2 ){
|
||||
pBt->readOnly = 1;
|
||||
}
|
||||
if( page1[19]>2 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
|
||||
/* If the write version is set to 2, this database should be accessed
|
||||
** in WAL mode. If the log is not already open, open it now. Then
|
||||
** return SQLITE_OK and return without populating BtShared.pPage1.
|
||||
** The caller detects this and calls this function again. This is
|
||||
** required as the version of page 1 currently in the page1 buffer
|
||||
** may not be the latest version - there may be a newer one in the log
|
||||
** file.
|
||||
*/
|
||||
if( page1[19]==2 && pBt->doNotUseWAL==0 ){
|
||||
int isOpen = 0;
|
||||
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto page1_init_failed;
|
||||
}else if( isOpen==0 ){
|
||||
releasePage(pPage1);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = SQLITE_NOTADB;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The maximum embedded fraction must be exactly 25%. And the minimum
|
||||
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
|
||||
@@ -2303,6 +2329,10 @@ static int lockBtree(BtShared *pBt){
|
||||
pageSize-usableSize);
|
||||
return rc;
|
||||
}
|
||||
if( nPageHeader>nPageFile ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto page1_init_failed;
|
||||
}
|
||||
if( usableSize<480 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
@@ -2333,6 +2363,7 @@ static int lockBtree(BtShared *pBt){
|
||||
pBt->minLeaf = (pBt->usableSize-12)*32/255 - 23;
|
||||
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
|
||||
pBt->pPage1 = pPage1;
|
||||
pBt->nPage = nPage;
|
||||
return SQLITE_OK;
|
||||
|
||||
page1_init_failed:
|
||||
@@ -2370,12 +2401,10 @@ static int newDatabase(BtShared *pBt){
|
||||
MemPage *pP1;
|
||||
unsigned char *data;
|
||||
int rc;
|
||||
int nPage;
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
|
||||
if( rc!=SQLITE_OK || nPage>0 ){
|
||||
return rc;
|
||||
if( pBt->nPage>0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pP1 = pBt->pPage1;
|
||||
assert( pP1!=0 );
|
||||
@@ -2401,6 +2430,8 @@ static int newDatabase(BtShared *pBt){
|
||||
put4byte(&data[36 + 4*4], pBt->autoVacuum);
|
||||
put4byte(&data[36 + 7*4], pBt->incrVacuum);
|
||||
#endif
|
||||
pBt->nPage = 1;
|
||||
data[31] = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -2490,6 +2521,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
||||
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
|
||||
if( SQLITE_OK!=rc ) goto trans_begun;
|
||||
|
||||
pBt->initiallyEmpty = pBt->nPage==0;
|
||||
do {
|
||||
/* Call lockBtree() until either pBt->pPage1 is populated or
|
||||
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
||||
@@ -2769,12 +2801,12 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
||||
*/
|
||||
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
||||
Pgno nFreeList; /* Number of pages still on the free-list */
|
||||
int rc;
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( iLastPg>nFin );
|
||||
|
||||
if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
|
||||
int rc;
|
||||
u8 eType;
|
||||
Pgno iPtrPage;
|
||||
|
||||
@@ -2850,7 +2882,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
||||
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
|
||||
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
|
||||
MemPage *pPg;
|
||||
int rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
|
||||
rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -2863,6 +2895,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
||||
iLastPg--;
|
||||
}
|
||||
sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
|
||||
pBt->nPage = iLastPg;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2885,7 +2918,11 @@ int sqlite3BtreeIncrVacuum(Btree *p){
|
||||
rc = SQLITE_DONE;
|
||||
}else{
|
||||
invalidateAllOverflowCache(pBt);
|
||||
rc = incrVacuumStep(pBt, 0, pagerPagecount(pBt));
|
||||
rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||
put4byte(&pBt->pPage1->aData[28], pBt->nPage);
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
@@ -2916,7 +2953,7 @@ static int autoVacuumCommit(BtShared *pBt){
|
||||
int nEntry; /* Number of entries on one ptrmap page */
|
||||
Pgno nOrig; /* Database size before freeing */
|
||||
|
||||
nOrig = pagerPagecount(pBt);
|
||||
nOrig = btreePagecount(pBt);
|
||||
if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
|
||||
/* It is not possible to create a database for which the final page
|
||||
** is either a pointer-map page or the pending-byte page. If one
|
||||
@@ -2941,11 +2978,12 @@ static int autoVacuumCommit(BtShared *pBt){
|
||||
rc = incrVacuumStep(pBt, nFin, iFree);
|
||||
}
|
||||
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
|
||||
rc = SQLITE_OK;
|
||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||
put4byte(&pBt->pPage1->aData[32], 0);
|
||||
put4byte(&pBt->pPage1->aData[36], 0);
|
||||
put4byte(&pBt->pPage1->aData[28], nFin);
|
||||
sqlite3PagerTruncateImage(pBt->pPager, nFin);
|
||||
pBt->nPage = nFin;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3PagerRollback(pPager);
|
||||
@@ -3195,6 +3233,11 @@ int sqlite3BtreeRollback(Btree *p){
|
||||
** call btreeGetPage() on page 1 again to make
|
||||
** sure pPage1->aData is set correctly. */
|
||||
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
|
||||
int nPage = get4byte(28+(u8*)pPage1->aData);
|
||||
testcase( nPage==0 );
|
||||
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
|
||||
testcase( pBt->nPage!=nPage );
|
||||
pBt->nPage = nPage;
|
||||
releasePage(pPage1);
|
||||
}
|
||||
assert( countWriteCursors(pBt)==0 );
|
||||
@@ -3232,17 +3275,13 @@ int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
|
||||
assert( pBt->readOnly==0 );
|
||||
assert( iStatement>0 );
|
||||
assert( iStatement>p->db->nSavepoint );
|
||||
if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){
|
||||
rc = SQLITE_INTERNAL;
|
||||
}else{
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
/* At the pager level, a statement transaction is a savepoint with
|
||||
** an index greater than all savepoints created explicitly using
|
||||
** SQL statements. It is illegal to open, release or rollback any
|
||||
** such savepoints while the statement transaction savepoint is active.
|
||||
*/
|
||||
rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
|
||||
}
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
/* At the pager level, a statement transaction is a savepoint with
|
||||
** an index greater than all savepoints created explicitly using
|
||||
** SQL statements. It is illegal to open, release or rollback any
|
||||
** such savepoints while the statement transaction savepoint is active.
|
||||
*/
|
||||
rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
}
|
||||
@@ -3268,7 +3307,12 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
|
||||
sqlite3BtreeEnter(p);
|
||||
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
|
||||
rc = newDatabase(pBt);
|
||||
pBt->nPage = get4byte(28 + pBt->pPage1->aData);
|
||||
if( pBt->nPage==0 ){
|
||||
sqlite3PagerPagecount(pBt->pPager, (int*)&pBt->nPage);
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
}
|
||||
@@ -3334,7 +3378,7 @@ static int btreeCursor(
|
||||
if( NEVER(wrFlag && pBt->readOnly) ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
if( iTable==1 && pagerPagecount(pBt)==0 ){
|
||||
if( iTable==1 && btreePagecount(pBt)==0 ){
|
||||
return SQLITE_EMPTY;
|
||||
}
|
||||
|
||||
@@ -3605,7 +3649,7 @@ static int getOverflowPage(
|
||||
iGuess++;
|
||||
}
|
||||
|
||||
if( iGuess<=pagerPagecount(pBt) ){
|
||||
if( iGuess<=btreePagecount(pBt) ){
|
||||
rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
|
||||
if( rc==SQLITE_OK && eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
|
||||
next = iGuess;
|
||||
@@ -4637,7 +4681,7 @@ static int allocateBtreePage(
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
pPage1 = pBt->pPage1;
|
||||
mxPage = pagerPagecount(pBt);
|
||||
mxPage = btreePagecount(pBt);
|
||||
n = get4byte(&pPage1->aData[36]);
|
||||
testcase( n==mxPage-1 );
|
||||
if( n>=mxPage ){
|
||||
@@ -4833,35 +4877,35 @@ static int allocateBtreePage(
|
||||
}else{
|
||||
/* There are no pages on the freelist, so create a new page at the
|
||||
** end of the file */
|
||||
int nPage = pagerPagecount(pBt);
|
||||
*pPgno = nPage + 1;
|
||||
|
||||
if( *pPgno==PENDING_BYTE_PAGE(pBt) ){
|
||||
(*pPgno)++;
|
||||
}
|
||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||
if( rc ) return rc;
|
||||
pBt->nPage++;
|
||||
if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
|
||||
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){
|
||||
/* If *pPgno refers to a pointer-map page, allocate two new pages
|
||||
** at the end of the file instead of one. The first allocated page
|
||||
** becomes a new pointer-map page, the second is used by the caller.
|
||||
*/
|
||||
MemPage *pPg = 0;
|
||||
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
|
||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
rc = btreeGetPage(pBt, *pPgno, &pPg, 0);
|
||||
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
|
||||
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
|
||||
rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerWrite(pPg->pDbPage);
|
||||
releasePage(pPg);
|
||||
}
|
||||
if( rc ) return rc;
|
||||
(*pPgno)++;
|
||||
if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; }
|
||||
pBt->nPage++;
|
||||
if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; }
|
||||
}
|
||||
#endif
|
||||
put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
|
||||
*pPgno = pBt->nPage;
|
||||
|
||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, 0);
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -5051,7 +5095,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
|
||||
while( nOvfl-- ){
|
||||
Pgno iNext = 0;
|
||||
MemPage *pOvfl = 0;
|
||||
if( ovflPgno<2 || ovflPgno>pagerPagecount(pBt) ){
|
||||
if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){
|
||||
/* 0 is not a legal page number and page 1 cannot be an
|
||||
** overflow page. Therefore if ovflPgno<2 or past the end of the
|
||||
** file the database must be corrupt. */
|
||||
@@ -6883,8 +6927,14 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
|
||||
releasePage(pRoot);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* When the new root page was allocated, page 1 was made writable in
|
||||
** order either to increase the database filesize, or to decrement the
|
||||
** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
|
||||
*/
|
||||
assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) );
|
||||
rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot);
|
||||
if( rc ){
|
||||
if( NEVER(rc) ){
|
||||
releasePage(pRoot);
|
||||
return rc;
|
||||
}
|
||||
@@ -6924,7 +6974,7 @@ static int clearDatabasePage(
|
||||
int i;
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
if( pgno>pagerPagecount(pBt) ){
|
||||
if( pgno>btreePagecount(pBt) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
@@ -7675,7 +7725,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
nRef = sqlite3PagerRefcount(pBt->pPager);
|
||||
sCheck.pBt = pBt;
|
||||
sCheck.pPager = pBt->pPager;
|
||||
sCheck.nPage = pagerPagecount(sCheck.pBt);
|
||||
sCheck.nPage = btreePagecount(sCheck.pBt);
|
||||
sCheck.mxErr = mxErr;
|
||||
sCheck.nErr = 0;
|
||||
sCheck.mallocFailed = 0;
|
||||
@@ -7943,3 +7993,39 @@ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
|
||||
pCur->isIncrblobHandle = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Set both the "read version" (single byte at byte offset 18) and
|
||||
** "write version" (single byte at byte offset 19) fields in the database
|
||||
** header to iVersion.
|
||||
*/
|
||||
int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
|
||||
BtShared *pBt = pBtree->pBt;
|
||||
int rc; /* Return code */
|
||||
|
||||
assert( pBtree->inTrans==TRANS_NONE );
|
||||
assert( iVersion==1 || iVersion==2 );
|
||||
|
||||
/* If setting the version fields to 1, do not automatically open the
|
||||
** WAL connection, even if the version fields are currently set to 2.
|
||||
*/
|
||||
pBt->doNotUseWAL = (iVersion==1);
|
||||
|
||||
rc = sqlite3BtreeBeginTrans(pBtree, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *aData = pBt->pPage1->aData;
|
||||
if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
|
||||
rc = sqlite3BtreeBeginTrans(pBtree, 2);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
aData[18] = (u8)iVersion;
|
||||
aData[19] = (u8)iVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pBt->doNotUseWAL = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ int sqlite3BtreeSyncDisabled(Btree*);
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeMaxPageCount(Btree*,int);
|
||||
u32 sqlite3BtreeLastPage(Btree*);
|
||||
int sqlite3BtreeSecureDelete(Btree*,int);
|
||||
int sqlite3BtreeGetReserve(Btree*);
|
||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
@@ -185,6 +186,8 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *);
|
||||
void sqlite3BtreeClearCursor(BtCursor *);
|
||||
|
||||
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
|
||||
|
||||
#ifndef NDEBUG
|
||||
int sqlite3BtreeCursorIsValid(BtCursor*);
|
||||
#endif
|
||||
|
||||
@@ -408,6 +408,7 @@ struct BtShared {
|
||||
u8 readOnly; /* True if the underlying file is readonly */
|
||||
u8 pageSizeFixed; /* True if the page size can no longer be changed */
|
||||
u8 secureDelete; /* True if secure_delete is enabled */
|
||||
u8 initiallyEmpty; /* Database is empty at start of transaction */
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
||||
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
||||
@@ -419,7 +420,9 @@ struct BtShared {
|
||||
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
|
||||
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
|
||||
u8 inTransaction; /* Transaction state */
|
||||
u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
|
||||
int nTransaction; /* Number of open transactions (read + write) */
|
||||
u32 nPage; /* Number of pages in the database */
|
||||
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
|
||||
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
|
||||
sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
|
||||
|
||||
+6
-1
@@ -353,14 +353,19 @@ FuncDef *sqlite3FindFunction(
|
||||
|
||||
/* If no match is found, search the built-in functions.
|
||||
**
|
||||
** If the SQLITE_PreferBuiltin flag is set, then search the built-in
|
||||
** functions even if a prior app-defined function was found. And give
|
||||
** priority to built-in functions.
|
||||
**
|
||||
** Except, if createFlag is true, that means that we are trying to
|
||||
** install a new function. Whatever FuncDef structure is returned will
|
||||
** have fields overwritten with new information appropriate for the
|
||||
** new function. But the FuncDefs for built-in functions are read-only.
|
||||
** So we must not search for built-ins when creating a new function.
|
||||
*/
|
||||
if( !createFlag && !pBest ){
|
||||
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
|
||||
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
|
||||
bestScore = 0;
|
||||
p = functionSearch(pHash, h, zName, nName);
|
||||
while( p ){
|
||||
int score = matchQuality(p, nArg, enc);
|
||||
|
||||
@@ -171,6 +171,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_AUTOINIT
|
||||
"OMIT_AUTOINIT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
"OMIT_AUTOMATIC_INDEX",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
"OMIT_AUTOVACUUM",
|
||||
#endif
|
||||
|
||||
+4
-13
@@ -314,10 +314,8 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
|
||||
** Set the time to the current time reported by the VFS
|
||||
*/
|
||||
static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
|
||||
double r;
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
sqlite3OsCurrentTime(db->pVfs, &r);
|
||||
p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD);
|
||||
p->validJD = 1;
|
||||
}
|
||||
|
||||
@@ -1038,22 +1036,15 @@ static void currentTimeFunc(
|
||||
time_t t;
|
||||
char *zFormat = (char *)sqlite3_user_data(context);
|
||||
sqlite3 *db;
|
||||
double rT;
|
||||
sqlite3_int64 iT;
|
||||
char zBuf[20];
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
UNUSED_PARAMETER(argv);
|
||||
|
||||
db = sqlite3_context_db_handle(context);
|
||||
sqlite3OsCurrentTime(db->pVfs, &rT);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
t = 86400.0*(rT - 2440587.5) + 0.5;
|
||||
#else
|
||||
/* without floating point support, rT will have
|
||||
** already lost fractional day precision.
|
||||
*/
|
||||
t = 86400 * (rT - 2440587) - 43200;
|
||||
#endif
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &iT);
|
||||
t = iT/1000 - 10000*(sqlite3_int64)21086676;
|
||||
#ifdef HAVE_GMTIME_R
|
||||
{
|
||||
struct tm sNow;
|
||||
|
||||
+29
-31
@@ -2353,27 +2353,12 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
}
|
||||
#endif
|
||||
case TK_VARIABLE: {
|
||||
VdbeOp *pOp;
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
assert( pExpr->u.zToken!=0 );
|
||||
assert( pExpr->u.zToken[0]!=0 );
|
||||
if( pExpr->u.zToken[1]==0
|
||||
&& (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable
|
||||
&& pOp->p1+pOp->p3==pExpr->iColumn
|
||||
&& pOp->p2+pOp->p3==target
|
||||
&& pOp->p4.z==0
|
||||
){
|
||||
/* If the previous instruction was a copy of the previous unnamed
|
||||
** parameter into the previous register, then simply increment the
|
||||
** repeat count on the prior instruction rather than making a new
|
||||
** instruction.
|
||||
*/
|
||||
pOp->p3++;
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iColumn, target, 1);
|
||||
if( pExpr->u.zToken[1]!=0 ){
|
||||
sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
|
||||
if( pExpr->u.zToken[1]!=0 ){
|
||||
sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3440,7 +3425,6 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
** an incorrect 0 or 1 could lead to a malfunction.
|
||||
*/
|
||||
int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
int i;
|
||||
if( pA==0||pB==0 ){
|
||||
return pB==pA ? 0 : 2;
|
||||
}
|
||||
@@ -3453,18 +3437,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
if( pA->op!=pB->op ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
|
||||
|
||||
if( pA->x.pList && pB->x.pList ){
|
||||
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 2;
|
||||
for(i=0; i<pA->x.pList->nExpr; i++){
|
||||
Expr *pExprA = pA->x.pList->a[i].pExpr;
|
||||
Expr *pExprB = pB->x.pList->a[i].pExpr;
|
||||
if( sqlite3ExprCompare(pExprA, pExprB) ) return 2;
|
||||
}
|
||||
}else if( pA->x.pList || pB->x.pList ){
|
||||
return 2;
|
||||
}
|
||||
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
|
||||
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( ExprHasProperty(pA, EP_IntValue) ){
|
||||
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
|
||||
@@ -3481,6 +3454,31 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare two ExprList objects. Return 0 if they are identical and
|
||||
** non-zero if they differ in any way.
|
||||
**
|
||||
** This routine might return non-zero for equivalent ExprLists. The
|
||||
** only consequence will be disabled optimizations. But this routine
|
||||
** must never return 0 if the two ExprList objects are different, or
|
||||
** a malfunction will result.
|
||||
**
|
||||
** Two NULL pointers are considered to be the same. But a NULL pointer
|
||||
** always differs from a non-NULL pointer.
|
||||
*/
|
||||
int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
|
||||
int i;
|
||||
if( pA==0 && pB==0 ) return 0;
|
||||
if( pA==0 || pB==0 ) return 1;
|
||||
if( pA->nExpr!=pB->nExpr ) return 1;
|
||||
for(i=0; i<pA->nExpr; i++){
|
||||
Expr *pExprA = pA->a[i].pExpr;
|
||||
Expr *pExprB = pB->a[i].pExpr;
|
||||
if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
|
||||
if( sqlite3ExprCompare(pExprA, pExprB) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new element to the pAggInfo->aCol[] array. Return the index of
|
||||
|
||||
+10
-12
@@ -1411,20 +1411,15 @@ static void groupConcatFinalize(sqlite3_context *context){
|
||||
}
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
** external linkage.
|
||||
** This routine does per-connection function registration. Most
|
||||
** of the built-in functions above are part of the global function set.
|
||||
** This routine only deals with those that are not global.
|
||||
*/
|
||||
void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions(db);
|
||||
#endif
|
||||
if( !db->mallocFailed ){
|
||||
int rc = sqlite3_overload_function(db, "MATCH", 2);
|
||||
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
int rc = sqlite3_overload_function(db, "MATCH", 2);
|
||||
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1592,4 +1587,7 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
sqlite3FuncDefInsert(pHash, &aFunc[i]);
|
||||
}
|
||||
sqlite3RegisterDateTimeFunctions();
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions();
|
||||
#endif
|
||||
}
|
||||
|
||||
+1
-1
@@ -846,7 +846,7 @@ void sqlite3Insert(
|
||||
if( pColumn->a[j].idx==i ) break;
|
||||
}
|
||||
}
|
||||
if( pColumn && j>=pColumn->nId ){
|
||||
if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
|
||||
|
||||
+140
-1
@@ -1186,6 +1186,143 @@ void *sqlite3_rollback_hook(
|
||||
return pRet;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
|
||||
** Invoke sqlite3_wal_checkpoint if the number of frames in the log file
|
||||
** is greater than sqlite3.pWalArg cast to an integer (the value configured by
|
||||
** wal_autocheckpoint()).
|
||||
*/
|
||||
int sqlite3WalDefaultHook(
|
||||
void *pClientData, /* Argument */
|
||||
sqlite3 *db, /* Connection */
|
||||
const char *zDb, /* Database */
|
||||
int nFrame /* Size of WAL */
|
||||
){
|
||||
if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){
|
||||
sqlite3_wal_checkpoint(db, zDb);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WAL */
|
||||
|
||||
/*
|
||||
** Configure an sqlite3_wal_hook() callback to automatically checkpoint
|
||||
** a database after committing a transaction if there are nFrame or
|
||||
** more frames in the log file. Passing zero or a negative value as the
|
||||
** nFrame parameter disables automatic checkpoints entirely.
|
||||
**
|
||||
** The callback registered by this function replaces any existing callback
|
||||
** registered using sqlite3_wal_hook(). Likewise, registering a callback
|
||||
** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
|
||||
** configured by this function.
|
||||
*/
|
||||
int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
if( nFrame>0 ){
|
||||
sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
|
||||
}else{
|
||||
sqlite3_wal_hook(db, 0, 0);
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register a callback to be invoked each time a transaction is written
|
||||
** into the write-ahead-log by this database connection.
|
||||
*/
|
||||
void *sqlite3_wal_hook(
|
||||
sqlite3 *db, /* Attach the hook to this db handle */
|
||||
int(*xCallback)(void *, sqlite3*, const char*, int),
|
||||
void *pArg /* First argument passed to xCallback() */
|
||||
){
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
void *pRet;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pRet = db->pWalArg;
|
||||
db->xWalCallback = xCallback;
|
||||
db->pWalArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return pRet;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
|
||||
** to contains a zero-length string, all attached databases are
|
||||
** checkpointed.
|
||||
*/
|
||||
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
return SQLITE_OK;
|
||||
#else
|
||||
int rc; /* Return code */
|
||||
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( zDb && zDb[0] ){
|
||||
iDb = sqlite3FindDbName(db, zDb);
|
||||
}
|
||||
if( iDb<0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
|
||||
}else{
|
||||
rc = sqlite3Checkpoint(db, iDb);
|
||||
sqlite3Error(db, rc, 0);
|
||||
}
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** Run a checkpoint on database iDb. This is a no-op if database iDb is
|
||||
** not currently open in WAL mode.
|
||||
**
|
||||
** If a transaction is open on the database being checkpointed, this
|
||||
** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
|
||||
** an error occurs while running the checkpoint, an SQLite error code is
|
||||
** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK.
|
||||
**
|
||||
** The mutex on database handle db should be held by the caller. The mutex
|
||||
** associated with the specific b-tree being checkpointed is taken by
|
||||
** this function while the checkpoint is running.
|
||||
**
|
||||
** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
|
||||
** checkpointed. If an error is encountered it is returned immediately -
|
||||
** no attempt is made to checkpoint any remaining databases.
|
||||
*/
|
||||
int sqlite3Checkpoint(sqlite3 *db, int iDb){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int i; /* Used to iterate through attached dbs */
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
|
||||
for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
|
||||
if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
if( sqlite3BtreeIsInReadTrans(pBt) ){
|
||||
rc = SQLITE_LOCKED;
|
||||
}else{
|
||||
sqlite3BtreeEnter(pBt);
|
||||
rc = sqlite3PagerCheckpoint(sqlite3BtreePager(pBt));
|
||||
sqlite3BtreeLeave(pBt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WAL */
|
||||
|
||||
/*
|
||||
** This function returns true if main-memory should be used instead of
|
||||
** a temporary file for transient pager files and statement journals.
|
||||
@@ -1608,7 +1745,7 @@ static int openDatabase(
|
||||
db->autoCommit = 1;
|
||||
db->nextAutovac = -1;
|
||||
db->nextPagesize = 0;
|
||||
db->flags |= SQLITE_ShortColNames
|
||||
db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex
|
||||
#if SQLITE_DEFAULT_FILE_FORMAT<4
|
||||
| SQLITE_LegacyFileFmt
|
||||
#endif
|
||||
@@ -1746,6 +1883,8 @@ static int openDatabase(
|
||||
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
|
||||
sqlite3GlobalConfig.nLookaside);
|
||||
|
||||
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
|
||||
|
||||
opendb_out:
|
||||
if( db ){
|
||||
assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
|
||||
|
||||
@@ -356,6 +356,7 @@ scratch_overflow:
|
||||
}else{
|
||||
p = sqlite3GlobalConfig.m.xMalloc(n);
|
||||
}
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
|
||||
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
|
||||
scratchAllocOut = p!=0;
|
||||
#endif
|
||||
@@ -376,6 +377,8 @@ void sqlite3ScratchFree(void *p){
|
||||
if( sqlite3GlobalConfig.pScratch==0
|
||||
|| p<sqlite3GlobalConfig.pScratch
|
||||
|| p>=(void*)mem0.aScratchFree ){
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
if( sqlite3GlobalConfig.bMemstat ){
|
||||
int iSize = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
@@ -416,6 +419,7 @@ static int isLookaside(sqlite3 *db, void *p){
|
||||
** sqlite3Malloc() or sqlite3_malloc().
|
||||
*/
|
||||
int sqlite3MallocSize(void *p){
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
||||
return sqlite3GlobalConfig.m.xSize(p);
|
||||
}
|
||||
int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
||||
@@ -423,6 +427,8 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
||||
if( isLookaside(db, p) ){
|
||||
return db->lookaside.sz;
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p,
|
||||
db ? (MEMTYPE_DB|MEMTYPE_HEAP) : MEMTYPE_HEAP) );
|
||||
return sqlite3GlobalConfig.m.xSize(p);
|
||||
}
|
||||
}
|
||||
@@ -432,6 +438,7 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
||||
*/
|
||||
void sqlite3_free(void *p){
|
||||
if( p==0 ) return;
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
||||
if( sqlite3GlobalConfig.bMemstat ){
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
|
||||
@@ -454,6 +461,8 @@ void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
db->lookaside.pFree = pBuf;
|
||||
db->lookaside.nOut--;
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
@@ -486,6 +495,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){
|
||||
mem0.alarmThreshold ){
|
||||
sqlite3MallocAlarm(nNew-nOld);
|
||||
}
|
||||
assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
|
||||
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
||||
if( pNew==0 && mem0.alarmCallback ){
|
||||
sqlite3MallocAlarm(nBytes);
|
||||
@@ -583,6 +593,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){
|
||||
if( !p && db ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
sqlite3MemdebugSetType(p,
|
||||
(db && db->lookaside.bEnabled) ? MEMTYPE_DB : MEMTYPE_HEAP);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -608,10 +620,14 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
pNew = sqlite3_realloc(p, n);
|
||||
if( !pNew ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
sqlite3MemdebugSetType(pNew,
|
||||
db->lookaside.bEnabled ? MEMTYPE_DB : MEMTYPE_HEAP);
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
|
||||
+44
-1
@@ -57,7 +57,8 @@ struct MemBlockHdr {
|
||||
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
|
||||
char nBacktrace; /* Number of backtraces on this alloc */
|
||||
char nBacktraceSlots; /* Available backtrace slots */
|
||||
short nTitle; /* Bytes of title; includes '\0' */
|
||||
u8 nTitle; /* Bytes of title; includes '\0' */
|
||||
u8 eType; /* Allocation type code */
|
||||
int iForeGuard; /* Guard word for sanity */
|
||||
};
|
||||
|
||||
@@ -265,6 +266,7 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
}
|
||||
mem.pLast = pHdr;
|
||||
pHdr->iForeGuard = FOREGUARD;
|
||||
pHdr->eType = MEMTYPE_HEAP;
|
||||
pHdr->nBacktraceSlots = mem.nBacktrace;
|
||||
pHdr->nTitle = mem.nTitle;
|
||||
if( mem.nBacktrace ){
|
||||
@@ -372,6 +374,47 @@ void sqlite3MemSetDefault(void){
|
||||
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the "type" of an allocation.
|
||||
*/
|
||||
void sqlite3MemdebugSetType(void *p, u8 eType){
|
||||
if( p ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD );
|
||||
pHdr->eType = eType;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the mask of type in eType matches the type of the
|
||||
** allocation p. Also return true if p==NULL.
|
||||
**
|
||||
** This routine is designed for use within an assert() statement, to
|
||||
** verify the type of an allocation. For example:
|
||||
**
|
||||
** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
|
||||
*/
|
||||
int sqlite3MemdebugHasType(void *p, u8 eType){
|
||||
int rc = 1;
|
||||
if( p ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
|
||||
assert( (pHdr->eType & (pHdr->eType-1))==0 ); /* Only one type bit set */
|
||||
if( (pHdr->eType&eType)==0 ){
|
||||
void **pBt;
|
||||
pBt = (void**)pHdr;
|
||||
pBt -= pHdr->nBacktraceSlots;
|
||||
backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(stderr));
|
||||
fprintf(stderr, "\n");
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set the number of backtrace levels kept for each allocation.
|
||||
** A value of zero turns off backtracing. The number is always rounded
|
||||
|
||||
+4
-5
@@ -196,11 +196,10 @@ static int memjrnlClose(sqlite3_file *pJfd){
|
||||
** exists purely as a contingency, in case some malfunction in some other
|
||||
** part of SQLite causes Sync to be called by mistake.
|
||||
*/
|
||||
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){ /*NO_TEST*/
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2); /*NO_TEST*/
|
||||
assert( 0 ); /*NO_TEST*/
|
||||
return SQLITE_OK; /*NO_TEST*/
|
||||
} /*NO_TEST*/
|
||||
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the size of the file in bytes.
|
||||
|
||||
+17
-14
@@ -31,23 +31,26 @@ static SQLITE_WSD int mutexIsInit = 0;
|
||||
*/
|
||||
int sqlite3MutexInit(void){
|
||||
int rc = SQLITE_OK;
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
|
||||
/* If the xMutexAlloc method has not been set, then the user did not
|
||||
** install a mutex implementation via sqlite3_config() prior to
|
||||
** sqlite3_initialize() being called. This block copies pointers to
|
||||
** the default implementation into the sqlite3GlobalConfig structure.
|
||||
*/
|
||||
sqlite3_mutex_methods *pFrom = sqlite3DefaultMutex();
|
||||
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
|
||||
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
|
||||
/* If the xMutexAlloc method has not been set, then the user did not
|
||||
** install a mutex implementation via sqlite3_config() prior to
|
||||
** sqlite3_initialize() being called. This block copies pointers to
|
||||
** the default implementation into the sqlite3GlobalConfig structure.
|
||||
*/
|
||||
sqlite3_mutex_methods *pFrom;
|
||||
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
|
||||
|
||||
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
|
||||
memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
|
||||
sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
|
||||
pTo->xMutexAlloc = pFrom->xMutexAlloc;
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
pFrom = sqlite3DefaultMutex();
|
||||
}else{
|
||||
pFrom = sqlite3NoopMutex();
|
||||
}
|
||||
rc = sqlite3GlobalConfig.mutex.xMutexInit();
|
||||
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
|
||||
memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
|
||||
sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
|
||||
pTo->xMutexAlloc = pFrom->xMutexAlloc;
|
||||
}
|
||||
rc = sqlite3GlobalConfig.mutex.xMutexInit();
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
GLOBAL(int, mutexIsInit) = 1;
|
||||
|
||||
+41
-25
@@ -27,15 +27,14 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_MUTEX_OMIT
|
||||
|
||||
#if defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG)
|
||||
#ifndef SQLITE_DEBUG
|
||||
/*
|
||||
** Stub routines for all mutex methods.
|
||||
**
|
||||
** This routines provide no mutual exclusion or error checking.
|
||||
*/
|
||||
static int noopMutexHeld(sqlite3_mutex *p){ return 1; }
|
||||
static int noopMutexNotheld(sqlite3_mutex *p){ return 1; }
|
||||
static int noopMutexInit(void){ return SQLITE_OK; }
|
||||
static int noopMutexEnd(void){ return SQLITE_OK; }
|
||||
static sqlite3_mutex *noopMutexAlloc(int id){ return (sqlite3_mutex*)8; }
|
||||
@@ -44,7 +43,7 @@ static void noopMutexEnter(sqlite3_mutex *p){ return; }
|
||||
static int noopMutexTry(sqlite3_mutex *p){ return SQLITE_OK; }
|
||||
static void noopMutexLeave(sqlite3_mutex *p){ return; }
|
||||
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
sqlite3_mutex_methods *sqlite3NoopMutex(void){
|
||||
static sqlite3_mutex_methods sMutex = {
|
||||
noopMutexInit,
|
||||
noopMutexEnd,
|
||||
@@ -54,15 +53,15 @@ sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
noopMutexTry,
|
||||
noopMutexLeave,
|
||||
|
||||
noopMutexHeld,
|
||||
noopMutexNotheld
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
return &sMutex;
|
||||
}
|
||||
#endif /* defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG) */
|
||||
#endif /* !SQLITE_DEBUG */
|
||||
|
||||
#if defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG)
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** In this implementation, error checking is provided for testing
|
||||
** and debugging purposes. The mutexes still do not provide any
|
||||
@@ -72,19 +71,21 @@ sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
/*
|
||||
** The mutex object
|
||||
*/
|
||||
struct sqlite3_mutex {
|
||||
typedef struct sqlite3_debug_mutex {
|
||||
int id; /* The mutex type */
|
||||
int cnt; /* Number of entries without a matching leave */
|
||||
};
|
||||
} sqlite3_debug_mutex;
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
|
||||
** intended for use inside assert() statements.
|
||||
*/
|
||||
static int debugMutexHeld(sqlite3_mutex *p){
|
||||
static int debugMutexHeld(sqlite3_mutex *pX){
|
||||
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
|
||||
return p==0 || p->cnt>0;
|
||||
}
|
||||
static int debugMutexNotheld(sqlite3_mutex *p){
|
||||
static int debugMutexNotheld(sqlite3_mutex *pX){
|
||||
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
|
||||
return p==0 || p->cnt==0;
|
||||
}
|
||||
|
||||
@@ -100,8 +101,8 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
|
||||
** that means that a mutex could not be allocated.
|
||||
*/
|
||||
static sqlite3_mutex *debugMutexAlloc(int id){
|
||||
static sqlite3_mutex aStatic[6];
|
||||
sqlite3_mutex *pNew = 0;
|
||||
static sqlite3_debug_mutex aStatic[6];
|
||||
sqlite3_debug_mutex *pNew = 0;
|
||||
switch( id ){
|
||||
case SQLITE_MUTEX_FAST:
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
@@ -120,13 +121,14 @@ static sqlite3_mutex *debugMutexAlloc(int id){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
return (sqlite3_mutex*)pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine deallocates a previously allocated mutex.
|
||||
*/
|
||||
static void debugMutexFree(sqlite3_mutex *p){
|
||||
static void debugMutexFree(sqlite3_mutex *pX){
|
||||
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
|
||||
assert( p->cnt==0 );
|
||||
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
sqlite3_free(p);
|
||||
@@ -143,12 +145,14 @@ static void debugMutexFree(sqlite3_mutex *p){
|
||||
** can enter. If the same thread tries to enter any other kind of mutex
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
static void debugMutexEnter(sqlite3_mutex *p){
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
|
||||
static void debugMutexEnter(sqlite3_mutex *pX){
|
||||
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
|
||||
p->cnt++;
|
||||
}
|
||||
static int debugMutexTry(sqlite3_mutex *p){
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
|
||||
static int debugMutexTry(sqlite3_mutex *pX){
|
||||
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
|
||||
p->cnt++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -159,13 +163,14 @@ static int debugMutexTry(sqlite3_mutex *p){
|
||||
** is undefined if the mutex is not currently entered or
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
static void debugMutexLeave(sqlite3_mutex *p){
|
||||
assert( debugMutexHeld(p) );
|
||||
static void debugMutexLeave(sqlite3_mutex *pX){
|
||||
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
|
||||
assert( debugMutexHeld(pX) );
|
||||
p->cnt--;
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
|
||||
}
|
||||
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
sqlite3_mutex_methods *sqlite3NoopMutex(void){
|
||||
static sqlite3_mutex_methods sMutex = {
|
||||
debugMutexInit,
|
||||
debugMutexEnd,
|
||||
@@ -181,4 +186,15 @@ sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
|
||||
return &sMutex;
|
||||
}
|
||||
#endif /* defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG) */
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
|
||||
** is used regardless of the run-time threadsafety setting.
|
||||
*/
|
||||
#ifdef SQLITE_MUTEX_NOOP
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
return sqliteNoopMutex();
|
||||
}
|
||||
#endif /* SQLITE_MUTEX_NOOP */
|
||||
#endif /* SQLITE_MUTEX_OMIT */
|
||||
|
||||
@@ -157,6 +157,7 @@ int sqlite3_unlock_notify(
|
||||
|
||||
if( xNotify==0 ){
|
||||
removeFromBlockedList(db);
|
||||
db->pBlockingConnection = 0;
|
||||
db->pUnlockConnection = 0;
|
||||
db->xUnlockNotify = 0;
|
||||
db->pUnlockArg = 0;
|
||||
|
||||
@@ -98,6 +98,24 @@ int sqlite3OsSectorSize(sqlite3_file *id){
|
||||
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
|
||||
return id->pMethods->xDeviceCharacteristics(id);
|
||||
}
|
||||
int sqlite3OsShmOpen(sqlite3_file *id){
|
||||
return id->pMethods->xShmOpen(id);
|
||||
}
|
||||
int sqlite3OsShmSize(sqlite3_file *id, int reqSize, int *pNewSize){
|
||||
return id->pMethods->xShmSize(id, reqSize, pNewSize);
|
||||
}
|
||||
int sqlite3OsShmGet(sqlite3_file *id, int reqSize, int *pSize, void **pp){
|
||||
return id->pMethods->xShmGet(id, reqSize, pSize, pp);
|
||||
}
|
||||
int sqlite3OsShmRelease(sqlite3_file *id){
|
||||
return id->pMethods->xShmRelease(id);
|
||||
}
|
||||
int sqlite3OsShmLock(sqlite3_file *id, int desiredLock, int *pGotLock){
|
||||
return id->pMethods->xShmLock(id, desiredLock, pGotLock);
|
||||
}
|
||||
int sqlite3OsShmClose(sqlite3_file *id, int deleteFlag){
|
||||
return id->pMethods->xShmClose(id, deleteFlag);
|
||||
}
|
||||
|
||||
/*
|
||||
** The next group of routines are convenience wrappers around the
|
||||
@@ -161,8 +179,16 @@ int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
return pVfs->xSleep(pVfs, nMicro);
|
||||
}
|
||||
int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return pVfs->xCurrentTime(pVfs, pTimeOut);
|
||||
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
|
||||
int rc;
|
||||
if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
|
||||
rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
|
||||
}else{
|
||||
double r;
|
||||
rc = pVfs->xCurrentTime(pVfs, &r);
|
||||
*pTimeOut = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sqlite3OsOpenMalloc(
|
||||
|
||||
@@ -243,6 +243,12 @@ int sqlite3OsFileControl(sqlite3_file*,int,void*);
|
||||
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
|
||||
int sqlite3OsSectorSize(sqlite3_file *id);
|
||||
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
|
||||
int sqlite3OsShmOpen(sqlite3_file *id);
|
||||
int sqlite3OsShmSize(sqlite3_file *id, int, int*);
|
||||
int sqlite3OsShmGet(sqlite3_file *id, int, int*, void**);
|
||||
int sqlite3OsShmRelease(sqlite3_file *id);
|
||||
int sqlite3OsShmLock(sqlite3_file *id, int, int*);
|
||||
int sqlite3OsShmClose(sqlite3_file *id, int);
|
||||
|
||||
/*
|
||||
** Functions for accessing sqlite3_vfs methods
|
||||
@@ -259,7 +265,7 @@ void sqlite3OsDlClose(sqlite3_vfs *, void *);
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
|
||||
int sqlite3OsSleep(sqlite3_vfs *, int);
|
||||
int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
|
||||
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
|
||||
|
||||
/*
|
||||
** Convenience functions for opening and closing files using
|
||||
|
||||
@@ -40,6 +40,7 @@ int sqlite3OSTrace = 0;
|
||||
if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D) \
|
||||
if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
|
||||
#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
|
||||
#else
|
||||
#define OSTRACE1(X)
|
||||
#define OSTRACE2(X,Y)
|
||||
@@ -48,6 +49,7 @@ int sqlite3OSTrace = 0;
|
||||
#define OSTRACE5(X,Y,Z,A,B)
|
||||
#define OSTRACE6(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D)
|
||||
#define OSTRACE(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -1111,7 +1111,7 @@ int sqlite3_os_init(void){
|
||||
os2Randomness, /* xRandomness */
|
||||
os2Sleep, /* xSleep */
|
||||
os2CurrentTime, /* xCurrentTime */
|
||||
os2GetLastError /* xGetLastError */
|
||||
os2GetLastError, /* xGetLastError */
|
||||
};
|
||||
sqlite3_vfs_register(&os2Vfs, 1);
|
||||
initUconvObjects();
|
||||
|
||||
+885
-30
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1912,7 +1912,7 @@ int sqlite3_os_init(void){
|
||||
winRandomness, /* xRandomness */
|
||||
winSleep, /* xSleep */
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError /* xGetLastError */
|
||||
winGetLastError, /* xGetLastError */
|
||||
};
|
||||
|
||||
sqlite3_vfs_register(&winVfs, 1);
|
||||
|
||||
+989
-362
File diff suppressed because it is too large
Load Diff
@@ -76,6 +76,7 @@ typedef struct PgHdr DbPage;
|
||||
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
|
||||
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
|
||||
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
|
||||
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
|
||||
|
||||
/*
|
||||
** The remainder of this file contains the declarations of the functions
|
||||
@@ -133,9 +134,16 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
|
||||
int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
|
||||
int sqlite3PagerSharedLock(Pager *pPager);
|
||||
|
||||
int sqlite3PagerCheckpoint(Pager *pPager);
|
||||
int sqlite3PagerWalSupported(Pager *pPager);
|
||||
int sqlite3PagerWalCallback(Pager *pPager);
|
||||
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
||||
int sqlite3PagerCloseWal(Pager *pPager);
|
||||
|
||||
/* Functions used to query pager state and configuration. */
|
||||
u8 sqlite3PagerIsreadonly(Pager*);
|
||||
int sqlite3PagerRefcount(Pager*);
|
||||
int sqlite3PagerMemUsed(Pager*);
|
||||
const char *sqlite3PagerFilename(Pager*);
|
||||
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
|
||||
sqlite3_file *sqlite3PagerFile(Pager*);
|
||||
|
||||
+6
-1
@@ -407,7 +407,12 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
|
||||
PgHdr *pNext;
|
||||
for(p=pCache->pDirty; p; p=pNext){
|
||||
pNext = p->pDirtyNext;
|
||||
if( p->pgno>pgno ){
|
||||
/* This routine never gets call with a positive pgno except right
|
||||
** after sqlite3PcacheCleanAll(). So if there are dirty pages,
|
||||
** it must be that pgno==0.
|
||||
*/
|
||||
assert( p->pgno>0 );
|
||||
if( ALWAYS(p->pgno>pgno) ){
|
||||
assert( p->flags&PGHDR_DIRTY );
|
||||
sqlite3PcacheMakeClean(p);
|
||||
}
|
||||
|
||||
+5
-1
@@ -173,6 +173,7 @@ static void *pcache1Alloc(int nByte){
|
||||
int sz = sqlite3MallocSize(p);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
|
||||
}
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@@ -190,7 +191,10 @@ static void pcache1Free(void *p){
|
||||
pSlot->pNext = pcache1.pFree;
|
||||
pcache1.pFree = pSlot;
|
||||
}else{
|
||||
int iSize = sqlite3MallocSize(p);
|
||||
int iSize;
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
iSize = sqlite3MallocSize(p);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
+90
-40
@@ -173,6 +173,9 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
{ "legacy_file_format", SQLITE_LegacyFileFmt },
|
||||
{ "fullfsync", SQLITE_FullFSync },
|
||||
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
{ "automatic_index", SQLITE_AutoIndex },
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ "sql_trace", SQLITE_SqlTrace },
|
||||
{ "vdbe_listing", SQLITE_VdbeListing },
|
||||
@@ -254,6 +257,31 @@ static const char *actionName(u8 action){
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
|
||||
** defined in pager.h. This function returns the associated lowercase
|
||||
** journal-mode name.
|
||||
*/
|
||||
const char *sqlite3JournalModename(int eMode){
|
||||
static char * const azModeName[] = {
|
||||
"delete", "persist", "off", "truncate", "memory"
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
, "wal"
|
||||
#endif
|
||||
};
|
||||
assert( PAGER_JOURNALMODE_DELETE==0 );
|
||||
assert( PAGER_JOURNALMODE_PERSIST==1 );
|
||||
assert( PAGER_JOURNALMODE_OFF==2 );
|
||||
assert( PAGER_JOURNALMODE_TRUNCATE==3 );
|
||||
assert( PAGER_JOURNALMODE_MEMORY==4 );
|
||||
assert( PAGER_JOURNALMODE_WAL==5 );
|
||||
assert( eMode>=0 && eMode<=ArraySize(azModeName) );
|
||||
|
||||
if( eMode==ArraySize(azModeName) ) return 0;
|
||||
return azModeName[eMode];
|
||||
}
|
||||
|
||||
/*
|
||||
** Process a pragma statement.
|
||||
**
|
||||
@@ -326,11 +354,11 @@ void sqlite3Pragma(
|
||||
** page cache size value and the persistent page cache size value
|
||||
** stored in the database file.
|
||||
**
|
||||
** The default cache size is stored in meta-value 2 of page 1 of the
|
||||
** database file. The cache size is actually the absolute value of
|
||||
** this memory location. The sign of meta-value 2 determines the
|
||||
** synchronous setting. A negative value means synchronous is off
|
||||
** and a positive value means synchronous is on.
|
||||
** Older versions of SQLite would set the default cache size to a
|
||||
** negative number to indicate synchronous=OFF. These days, synchronous
|
||||
** is always on by default regardless of the sign of the default cache
|
||||
** size. But continue to take the absolute value of the default cache
|
||||
** size of historical compatibility.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
|
||||
static const VdbeOpList getCacheSize[] = {
|
||||
@@ -359,10 +387,6 @@ void sqlite3Pragma(
|
||||
if( size<0 ) size = -size;
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, BTREE_DEFAULT_CACHE_SIZE);
|
||||
addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
@@ -507,21 +531,25 @@ void sqlite3Pragma(
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]journal_mode
|
||||
** PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory)
|
||||
** PRAGMA [database.]journal_mode =
|
||||
** (delete|persist|off|truncate|memory|wal|off)
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
|
||||
int eMode;
|
||||
static char * const azModeName[] = {
|
||||
"delete", "persist", "off", "truncate", "memory"
|
||||
};
|
||||
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
|
||||
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
|
||||
|
||||
if( zRight==0 ){
|
||||
eMode = PAGER_JOURNALMODE_QUERY;
|
||||
}else{
|
||||
const char *zMode;
|
||||
int n = sqlite3Strlen30(zRight);
|
||||
eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1;
|
||||
while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){
|
||||
eMode--;
|
||||
for(eMode=0; (zMode = sqlite3JournalModename(eMode)); eMode++){
|
||||
if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
|
||||
}
|
||||
if( !zMode ){
|
||||
eMode = PAGER_JOURNALMODE_QUERY;
|
||||
}
|
||||
}
|
||||
if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
|
||||
@@ -530,39 +558,31 @@ void sqlite3Pragma(
|
||||
** the journal-mode of the main database).
|
||||
*/
|
||||
eMode = db->dfltJournalMode;
|
||||
sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3JournalModename(eMode), P4_STATIC);
|
||||
}else{
|
||||
Pager *pPager;
|
||||
int ii;
|
||||
|
||||
if( pId2->n==0 ){
|
||||
/* This indicates that no database name was specified as part
|
||||
** of the PRAGMA command. In this case the journal-mode must be
|
||||
** set on all attached databases, as well as the main db file.
|
||||
/* When there is no database name before the "journal_mode" keyword
|
||||
** in the PRAGMA, then the journal-mode will be set on
|
||||
** all attached databases, as well as the main db file.
|
||||
**
|
||||
** Also, the sqlite3.dfltJournalMode variable is set so that
|
||||
** any subsequently attached databases also use the specified
|
||||
** journal mode.
|
||||
*/
|
||||
int ii;
|
||||
assert(pDb==&db->aDb[0]);
|
||||
for(ii=1; ii<db->nDb; ii++){
|
||||
if( db->aDb[ii].pBt ){
|
||||
pPager = sqlite3BtreePager(db->aDb[ii].pBt);
|
||||
sqlite3PagerJournalMode(pPager, eMode);
|
||||
}
|
||||
}
|
||||
db->dfltJournalMode = (u8)eMode;
|
||||
}
|
||||
pPager = sqlite3BtreePager(pDb->pBt);
|
||||
eMode = sqlite3PagerJournalMode(pPager, eMode);
|
||||
|
||||
for(ii=db->nDb-1; ii>=0; ii--){
|
||||
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
|
||||
sqlite3VdbeUsesBtree(v, ii);
|
||||
sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( eMode==PAGER_JOURNALMODE_DELETE
|
||||
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|
||||
|| eMode==PAGER_JOURNALMODE_PERSIST
|
||||
|| eMode==PAGER_JOURNALMODE_OFF
|
||||
|| eMode==PAGER_JOURNALMODE_MEMORY );
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0,
|
||||
azModeName[eMode], P4_STATIC);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}else
|
||||
|
||||
@@ -1380,6 +1400,36 @@ void sqlite3Pragma(
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** PRAGMA [database.]wal_checkpoint
|
||||
**
|
||||
** Checkpoint the database.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeAddOp3(v, OP_Checkpoint, pId2->z?iDb:SQLITE_MAX_ATTACHED, 0, 0);
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA wal_autocheckpoint
|
||||
** PRAGMA wal_autocheckpoint = N
|
||||
**
|
||||
** Configure a database connection to automatically checkpoint a database
|
||||
** after accumulating N frames in the log. Or query for the current value
|
||||
** of N.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
|
||||
if( zRight ){
|
||||
int nAuto = atoi(zRight);
|
||||
sqlite3_wal_autocheckpoint(db, nAuto);
|
||||
}
|
||||
returnSingleInt(pParse, "wal_autocheckpoint",
|
||||
db->xWalCallback==sqlite3WalDefaultHook ?
|
||||
SQLITE_PTR_TO_INT(db->pWalArg) : 0);
|
||||
}else
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
/*
|
||||
** Report the current state of file logs for all databases
|
||||
|
||||
+7
-5
@@ -73,15 +73,15 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
** or executed. All the parser does is build the internal data
|
||||
** structures that describe the table, index, or view.
|
||||
*/
|
||||
char *zErr;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
assert( db->init.busy );
|
||||
db->init.iDb = iDb;
|
||||
db->init.newTnum = atoi(argv[1]);
|
||||
db->init.orphanTrigger = 0;
|
||||
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
|
||||
rc = sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
|
||||
db->init.iDb = 0;
|
||||
assert( rc!=SQLITE_OK || zErr==0 );
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( db->init.orphanTrigger ){
|
||||
assert( iDb==1 );
|
||||
@@ -90,11 +90,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
|
||||
corruptSchema(pData, argv[0], zErr);
|
||||
corruptSchema(pData, argv[0], sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
sqlite3DbFree(db, zErr);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}else if( argv[0]==0 ){
|
||||
corruptSchema(pData, 0, 0);
|
||||
}else{
|
||||
@@ -579,6 +579,7 @@ static int sqlite3Prepare(
|
||||
sqlite3VtabUnlockList(db);
|
||||
|
||||
pParse->db = db;
|
||||
pParse->nQueryLoop = (double)1;
|
||||
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
|
||||
char *zSqlCopy;
|
||||
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
||||
@@ -600,6 +601,7 @@ static int sqlite3Prepare(
|
||||
}else{
|
||||
sqlite3RunParser(pParse, zSql, &zErrMsg);
|
||||
}
|
||||
assert( 1==(int)pParse->nQueryLoop );
|
||||
|
||||
if( db->mallocFailed ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
|
||||
+3
-1
@@ -403,7 +403,7 @@ lookupname_end:
|
||||
|
||||
/*
|
||||
** Allocate and return a pointer to an expression to load the column iCol
|
||||
** from datasource iSrc datasource in SrcList pSrc.
|
||||
** from datasource iSrc in SrcList pSrc.
|
||||
*/
|
||||
Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
|
||||
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
|
||||
@@ -415,6 +415,8 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
|
||||
p->iColumn = -1;
|
||||
}else{
|
||||
p->iColumn = (ynVar)iCol;
|
||||
testcase( iCol==BMS );
|
||||
testcase( iCol==BMS-1 );
|
||||
pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
|
||||
}
|
||||
ExprSetProperty(p, EP_Resolved);
|
||||
|
||||
+27
-3
@@ -2526,8 +2526,8 @@ static void substSelect(
|
||||
** (14) The subquery does not use OFFSET
|
||||
**
|
||||
** (15) The outer query is not part of a compound select or the
|
||||
** subquery does not have both an ORDER BY and a LIMIT clause.
|
||||
** (See ticket #2339)
|
||||
** subquery does not have a LIMIT clause.
|
||||
** (See ticket #2339 and ticket [02a8e81d44]).
|
||||
**
|
||||
** (16) The outer query is not an aggregate or the subquery does
|
||||
** not contain ORDER BY. (Ticket #2942) This used to not matter
|
||||
@@ -2610,7 +2610,7 @@ static int flattenSubquery(
|
||||
** and (14). */
|
||||
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
|
||||
if( pSub->pOffset ) return 0; /* Restriction (14) */
|
||||
if( p->pRightmost && pSub->pLimit && pSub->pOrderBy ){
|
||||
if( p->pRightmost && pSub->pLimit ){
|
||||
return 0; /* Restriction (15) */
|
||||
}
|
||||
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
|
||||
@@ -3498,6 +3498,18 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
}
|
||||
}
|
||||
|
||||
/* Before populating the accumulator registers, clear the column cache.
|
||||
** Otherwise, if any of the required column values are already present
|
||||
** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value
|
||||
** to pC->iMem. But by the time the value is used, the original register
|
||||
** may have been used, invalidating the underlying buffer holding the
|
||||
** text or blob value. See ticket [883034dcb5].
|
||||
**
|
||||
** Another solution would be to change the OP_SCopy used to copy cached
|
||||
** values to an OP_Copy.
|
||||
*/
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
|
||||
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
|
||||
}
|
||||
@@ -3706,6 +3718,18 @@ int sqlite3Select(
|
||||
isDistinct = 0;
|
||||
}
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then disable the ORDER BY clause since the GROUP BY
|
||||
** will cause elements to come out in the correct order. This is
|
||||
** an optimization - the correct answer should result regardless.
|
||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
|
||||
** to disable this optimization for testing purposes.
|
||||
*/
|
||||
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
|
||||
&& (db->flags & SQLITE_GroupByOrder)==0 ){
|
||||
pOrderBy = 0;
|
||||
}
|
||||
|
||||
/* If there is an ORDER BY clause, then this sorting
|
||||
** index might end up being unused if the data can be
|
||||
** extracted in pre-sorted order. If that is the case, then the
|
||||
|
||||
+4
-4
@@ -2578,7 +2578,6 @@ int main(int argc, char **argv){
|
||||
*/
|
||||
if( zFirstCmd[0]=='.' ){
|
||||
rc = do_meta_command(zFirstCmd, &data);
|
||||
return rc;
|
||||
}else{
|
||||
open_db(&data);
|
||||
rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
|
||||
@@ -2625,9 +2624,10 @@ int main(int argc, char **argv){
|
||||
}
|
||||
}
|
||||
set_table_name(&data, 0);
|
||||
if( db ){
|
||||
if( sqlite3_close(db)!=SQLITE_OK ){
|
||||
fprintf(stderr,"Error: cannot close database \"%s\"\n", sqlite3_errmsg(db));
|
||||
if( data.db ){
|
||||
if( sqlite3_close(data.db)!=SQLITE_OK ){
|
||||
fprintf(stderr,"Error: cannot close database \"%s\"\n",
|
||||
sqlite3_errmsg(db));
|
||||
rc++;
|
||||
}
|
||||
}
|
||||
|
||||
+184
-57
@@ -141,7 +141,6 @@ const char *sqlite3_libversion(void);
|
||||
const char *sqlite3_sourceid(void);
|
||||
int sqlite3_libversion_number(void);
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
|
||||
**
|
||||
@@ -164,9 +163,10 @@ int sqlite3_libversion_number(void);
|
||||
** See also: SQL functions [sqlite_compileoption_used()] and
|
||||
** [sqlite_compileoption_get()] and the [compile_options pragma].
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
int sqlite3_compileoption_used(const char *zOptName);
|
||||
const char *sqlite3_compileoption_get(int N);
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** CAPI3REF: Test To See If The Library Is Threadsafe
|
||||
@@ -653,6 +653,14 @@ struct sqlite3_io_methods {
|
||||
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
|
||||
int (*xSectorSize)(sqlite3_file*);
|
||||
int (*xDeviceCharacteristics)(sqlite3_file*);
|
||||
/* Methods above are valid for version 1 */
|
||||
int (*xShmOpen)(sqlite3_file*);
|
||||
int (*xShmSize)(sqlite3_file*, int reqSize, int *pNewSize);
|
||||
int (*xShmGet)(sqlite3_file*, int reqSize, int *pSize, void**);
|
||||
int (*xShmRelease)(sqlite3_file*);
|
||||
int (*xShmLock)(sqlite3_file*, int desiredLock, int *gotLock);
|
||||
int (*xShmClose)(sqlite3_file*, int deleteFlag);
|
||||
/* Methods above are valid for version 2 */
|
||||
/* Additional methods may be added in future releases */
|
||||
};
|
||||
|
||||
@@ -819,7 +827,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
||||
*/
|
||||
typedef struct sqlite3_vfs sqlite3_vfs;
|
||||
struct sqlite3_vfs {
|
||||
int iVersion; /* Structure version number */
|
||||
int iVersion; /* Structure version number (currently 2) */
|
||||
int szOsFile; /* Size of subclassed sqlite3_file */
|
||||
int mxPathname; /* Maximum file pathname length */
|
||||
sqlite3_vfs *pNext; /* Next registered VFS */
|
||||
@@ -838,8 +846,17 @@ struct sqlite3_vfs {
|
||||
int (*xSleep)(sqlite3_vfs*, int microseconds);
|
||||
int (*xCurrentTime)(sqlite3_vfs*, double*);
|
||||
int (*xGetLastError)(sqlite3_vfs*, int, char *);
|
||||
/* New fields may be appended in figure versions. The iVersion
|
||||
** value will increment whenever this happens. */
|
||||
/*
|
||||
** The methods above are in version 1 of the sqlite_vfs object
|
||||
** definition. Those that follow are added in version 2 or later
|
||||
*/
|
||||
int (*xRename)(sqlite3_vfs*, const char *zOld, const char *zNew, int dirSync);
|
||||
int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
|
||||
/*
|
||||
** The methods above are in versions 1 and 2 of the sqlite_vfs object.
|
||||
** New fields may be appended in figure versions. The iVersion
|
||||
** value will increment whenever this happens.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -859,6 +876,20 @@ struct sqlite3_vfs {
|
||||
#define SQLITE_ACCESS_READWRITE 1
|
||||
#define SQLITE_ACCESS_READ 2
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags for the xShmLock VFS method
|
||||
**
|
||||
** These integer constants define the various locking states that
|
||||
** an sqlite3_shm object can be in.
|
||||
*/
|
||||
#define SQLITE_SHM_UNLOCK 0
|
||||
#define SQLITE_SHM_READ 1
|
||||
#define SQLITE_SHM_READ_FULL 2
|
||||
#define SQLITE_SHM_WRITE 3
|
||||
#define SQLITE_SHM_PENDING 4
|
||||
#define SQLITE_SHM_CHECKPOINT 5
|
||||
#define SQLITE_SHM_RECOVER 6
|
||||
|
||||
/*
|
||||
** CAPI3REF: Initialize The SQLite Library
|
||||
**
|
||||
@@ -968,11 +999,10 @@ int sqlite3_os_end(void);
|
||||
** ^If the option is unknown or SQLite is unable to set the option
|
||||
** then this routine returns a non-zero [error code].
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
|
||||
int sqlite3_config(int, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configure database connections
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** The sqlite3_db_config() interface is used to make configuration
|
||||
** changes to a [database connection]. The interface is similar to
|
||||
@@ -992,11 +1022,10 @@ SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
|
||||
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
|
||||
** the call is considered successful.
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
|
||||
int sqlite3_db_config(sqlite3*, int op, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Memory Allocation Routines
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** An instance of this object defines the interface between SQLite
|
||||
** and low-level memory allocation routines.
|
||||
@@ -1078,7 +1107,6 @@ struct sqlite3_mem_methods {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configuration Options
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** These constants are the available integer configuration options that
|
||||
** can be passed as the first argument to the [sqlite3_config()] interface.
|
||||
@@ -1264,6 +1292,24 @@ struct sqlite3_mem_methods {
|
||||
** [sqlite3_pcache_methods] object. SQLite copies of the current
|
||||
** page cache implementation into that object.)^ </dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_LOG</dt>
|
||||
** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
|
||||
** function with a call signature of void(*)(void*,int,const char*),
|
||||
** and a pointer to void. ^If the function pointer is not NULL, it is
|
||||
** invoked by [sqlite3_log()] to process each logging event. ^If the
|
||||
** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
|
||||
** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
|
||||
** passed through as the first parameter to the application-defined logger
|
||||
** function whenever that function is invoked. ^The second parameter to
|
||||
** the logger function is a copy of the first parameter to the corresponding
|
||||
** [sqlite3_log()] call and is intended to be a [result code] or an
|
||||
** [extended result code]. ^The third parameter passed to the logger is
|
||||
** log message after formatting via [sqlite3_snprintf()].
|
||||
** The SQLite logging interface is not reentrant; the logger function
|
||||
** supplied by the application must not invoke any SQLite interface.
|
||||
** In a multi-threaded application, the application-defined logger
|
||||
** function must be threadsafe. </dd>
|
||||
**
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
@@ -1284,8 +1330,7 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configuration Options
|
||||
** EXPERIMENTAL
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
**
|
||||
** These constants are the available integer configuration options that
|
||||
** can be passed as the second argument to the [sqlite3_db_config()] interface.
|
||||
@@ -2061,7 +2106,6 @@ int sqlite3_set_authorizer(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Tracing And Profiling Functions
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** These routines register callback functions that can be used for
|
||||
** tracing and profiling the execution of SQL statements.
|
||||
@@ -2079,7 +2123,7 @@ int sqlite3_set_authorizer(
|
||||
** the original statement text and an estimate of wall-clock time
|
||||
** of how long that statement took to run.
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
||||
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
||||
SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
|
||||
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
|
||||
|
||||
@@ -2872,6 +2916,14 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
||||
** be the case that the same database connection is being used by two or
|
||||
** more threads at the same moment in time.
|
||||
**
|
||||
** For all versions of SQLite up to and including 3.6.23.1, it was required
|
||||
** after sqlite3_step() returned anything other than [SQLITE_ROW] that
|
||||
** [sqlite3_reset()] be called before any subsequent invocation of
|
||||
** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way would
|
||||
** result in an [SQLITE_MISUSE] return from sqlite3_step(). But after
|
||||
** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()]
|
||||
** automatically in this circumstance rather than returning [SQLITE_MISUSE].
|
||||
**
|
||||
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
|
||||
** API always returns a generic error code, [SQLITE_ERROR], following any
|
||||
** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
|
||||
@@ -3684,7 +3736,7 @@ int sqlite3_collation_needed16(
|
||||
void(*)(void*,sqlite3*,int eTextRep,const void*)
|
||||
);
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/*
|
||||
** Specify the key for an encrypted database. This routine should be
|
||||
** called right after sqlite3_open().
|
||||
@@ -3867,8 +3919,6 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
|
||||
** an error or constraint causes an implicit rollback to occur.
|
||||
** ^The rollback callback is not invoked if a transaction is
|
||||
** automatically rolled back because the database connection is closed.
|
||||
** ^The rollback callback is not invoked if a transaction is
|
||||
** rolled back because a commit callback returned non-zero.
|
||||
**
|
||||
** See also the [sqlite3_update_hook()] interface.
|
||||
*/
|
||||
@@ -4154,8 +4204,6 @@ int sqlite3_auto_extension(void (*xEntryPoint)(void));
|
||||
void sqlite3_reset_auto_extension(void);
|
||||
|
||||
/*
|
||||
****** EXPERIMENTAL - subject to change without notice **************
|
||||
**
|
||||
** The interface to the virtual-table mechanism is currently considered
|
||||
** to be experimental. The interface might change in incompatible ways.
|
||||
** If this is a problem for you, do not use the interface at this time.
|
||||
@@ -4175,7 +4223,6 @@ typedef struct sqlite3_module sqlite3_module;
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Object
|
||||
** KEYWORDS: sqlite3_module {virtual table module}
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** This structure, sometimes called a a "virtual table module",
|
||||
** defines the implementation of a [virtual tables].
|
||||
@@ -4222,7 +4269,6 @@ struct sqlite3_module {
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Indexing Information
|
||||
** KEYWORDS: sqlite3_index_info
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** The sqlite3_index_info structure and its substructures is used to
|
||||
** pass information into and receive the reply from the [xBestIndex]
|
||||
@@ -4304,7 +4350,6 @@ struct sqlite3_index_info {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Register A Virtual Table Implementation
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^These routines are used to register a new [virtual table module] name.
|
||||
** ^Module names must be registered before
|
||||
@@ -4326,13 +4371,13 @@ struct sqlite3_index_info {
|
||||
** interface is equivalent to sqlite3_create_module_v2() with a NULL
|
||||
** destructor.
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_create_module(
|
||||
int sqlite3_create_module(
|
||||
sqlite3 *db, /* SQLite connection to register module with */
|
||||
const char *zName, /* Name of the module */
|
||||
const sqlite3_module *p, /* Methods for the module */
|
||||
void *pClientData /* Client data for xCreate/xConnect */
|
||||
);
|
||||
SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
|
||||
int sqlite3_create_module_v2(
|
||||
sqlite3 *db, /* SQLite connection to register module with */
|
||||
const char *zName, /* Name of the module */
|
||||
const sqlite3_module *p, /* Methods for the module */
|
||||
@@ -4343,7 +4388,6 @@ SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Instance Object
|
||||
** KEYWORDS: sqlite3_vtab
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** Every [virtual table module] implementation uses a subclass
|
||||
** of this object to describe a particular instance
|
||||
@@ -4369,7 +4413,6 @@ struct sqlite3_vtab {
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Cursor Object
|
||||
** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** Every [virtual table module] implementation uses a subclass of the
|
||||
** following structure to describe cursors that point into the
|
||||
@@ -4391,18 +4434,16 @@ struct sqlite3_vtab_cursor {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Declare The Schema Of A Virtual Table
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^The [xCreate] and [xConnect] methods of a
|
||||
** [virtual table module] call this interface
|
||||
** to declare the format (the names and datatypes of the columns) of
|
||||
** the virtual tables they implement.
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
||||
int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Overload A Function For A Virtual Table
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^(Virtual tables can provide alternative implementations of functions
|
||||
** using the [xFindFunction] method of the [virtual table module].
|
||||
@@ -4417,7 +4458,7 @@ SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
||||
** purpose is to be a placeholder function that can be overloaded
|
||||
** by a [virtual table].
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
|
||||
int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
|
||||
|
||||
/*
|
||||
** The interface to the virtual-table mechanism defined above (back up
|
||||
@@ -4427,8 +4468,6 @@ SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncNam
|
||||
**
|
||||
** When the virtual-table mechanism stabilizes, we will declare the
|
||||
** interface fixed, support it indefinitely, and remove this comment.
|
||||
**
|
||||
****** EXPERIMENTAL - subject to change without notice **************
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -4771,7 +4810,6 @@ void sqlite3_mutex_leave(sqlite3_mutex*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Methods Object
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** An instance of this structure defines the low-level routines
|
||||
** used to allocate and use mutexes.
|
||||
@@ -4988,7 +5026,6 @@ int sqlite3_test_control(int op, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^This interface is used to retrieve runtime status information
|
||||
** about the preformance of SQLite, and optionally to reset various
|
||||
@@ -5016,12 +5053,11 @@ int sqlite3_test_control(int op, ...);
|
||||
**
|
||||
** See also: [sqlite3_db_status()]
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** These integer constants designate various run-time status parameters
|
||||
** that can be returned by [sqlite3_status()].
|
||||
@@ -5108,14 +5144,15 @@ SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, i
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Status
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^This interface is used to retrieve runtime status information
|
||||
** about a single [database connection]. ^The first argument is the
|
||||
** database connection object to be interrogated. ^The second argument
|
||||
** is the parameter to interrogate. ^Currently, the only allowed value
|
||||
** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
|
||||
** Additional options will likely appear in future releases of SQLite.
|
||||
** is an integer constant, taken from the set of
|
||||
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
|
||||
** determiness the parameter to interrogate. The set of
|
||||
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
|
||||
** to grow in future releases of SQLite.
|
||||
**
|
||||
** ^The current value of the requested parameter is written into *pCur
|
||||
** and the highest instantaneous value is written into *pHiwtr. ^If
|
||||
@@ -5124,11 +5161,10 @@ SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, i
|
||||
**
|
||||
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters for database connections
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** These constants are the available integer "verbs" that can be passed as
|
||||
** the second argument to the [sqlite3_db_status()] interface.
|
||||
@@ -5143,14 +5179,21 @@ SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiw
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
|
||||
** <dd>This parameter returns the number of lookaside memory slots currently
|
||||
** checked out.</dd>)^
|
||||
**
|
||||
** <dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
||||
** <dd>^This parameter returns the approximate number of of bytes of heap
|
||||
** memory used by all pager caches associated with the database connection.
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||
** checked out.</dd>)^
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
|
||||
#define SQLITE_DBSTATUS_CACHE_USED 1
|
||||
#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Status
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^(Each prepared statement maintains various
|
||||
** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
|
||||
@@ -5172,11 +5215,10 @@ SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiw
|
||||
**
|
||||
** See also: [sqlite3_status()] and [sqlite3_db_status()].
|
||||
*/
|
||||
SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters for prepared statements
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** These preprocessor macros define integer codes that name counter
|
||||
** values associated with the [sqlite3_stmt_status()] interface.
|
||||
@@ -5194,14 +5236,21 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
** A non-zero value in this counter may indicate an opportunity to
|
||||
** improvement performance through careful use of indices.</dd>
|
||||
**
|
||||
** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
|
||||
** <dd>^This is the number of rows inserted into transient indices that
|
||||
** were created automatically in order to help joins run faster.
|
||||
** A non-zero value in this counter may indicate an opportunity to
|
||||
** improvement performance by adding permanent indices that do not
|
||||
** need to be reinitialized each time the statement is run.</dd>
|
||||
**
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
|
||||
#define SQLITE_STMTSTATUS_SORT 2
|
||||
#define SQLITE_STMTSTATUS_AUTOINDEX 3
|
||||
|
||||
/*
|
||||
** CAPI3REF: Custom Page Cache Object
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** The sqlite3_pcache type is opaque. It is implemented by
|
||||
** the pluggable module. The SQLite core has no knowledge of
|
||||
@@ -5216,7 +5265,6 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
/*
|
||||
** CAPI3REF: Application Defined Page Cache.
|
||||
** KEYWORDS: {page cache}
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
|
||||
** register an alternative page cache implementation by passing in an
|
||||
@@ -5358,7 +5406,6 @@ struct sqlite3_pcache_methods {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Online Backup Object
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** The sqlite3_backup object records state information about an ongoing
|
||||
** online backup operation. ^The sqlite3_backup object is created by
|
||||
@@ -5371,7 +5418,6 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Online Backup API.
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** The backup API copies the content of one database into another.
|
||||
** It is useful either for creating backups of databases or
|
||||
@@ -5440,10 +5486,14 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
|
||||
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
|
||||
**
|
||||
** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
|
||||
** database was opened read-only or if
|
||||
** the destination is an in-memory database with a different page size
|
||||
** from the source database.
|
||||
** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
|
||||
** <ol>
|
||||
** <li> the destination database was opened read-only, or
|
||||
** <li> the destination database is using write-ahead-log journaling
|
||||
** and the destination and source page sizes differ, or
|
||||
** <li> The destination database is an in-memory database and the
|
||||
** destination and source page sizes differ.
|
||||
** </ol>)^
|
||||
**
|
||||
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
|
||||
** the [sqlite3_busy_handler | busy-handler function]
|
||||
@@ -5559,7 +5609,6 @@ int sqlite3_backup_pagecount(sqlite3_backup *p);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Unlock Notification
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^When running in shared-cache mode, a database operation may fail with
|
||||
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
|
||||
@@ -5681,7 +5730,6 @@ int sqlite3_unlock_notify(
|
||||
|
||||
/*
|
||||
** CAPI3REF: String Comparison
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
|
||||
** compare the contents of two buffers containing UTF-8 strings in a
|
||||
@@ -5692,12 +5740,11 @@ int sqlite3_strnicmp(const char *, const char *, int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Error Logging Interface
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** ^The [sqlite3_log()] interface writes a message into the error log
|
||||
** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
|
||||
** ^If logging is enabled, the zFormat string and subsequent arguments are
|
||||
** passed through to [sqlite3_vmprintf()] to generate the final output string.
|
||||
** used with [sqlite3_snprintf()] to generate the final output string.
|
||||
**
|
||||
** The sqlite3_log() interface is intended for use by extensions such as
|
||||
** virtual tables, collating functions, and SQL functions. While there is
|
||||
@@ -5714,6 +5761,86 @@ int sqlite3_strnicmp(const char *, const char *, int);
|
||||
*/
|
||||
void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Write-Ahead Log Commit Hook
|
||||
**
|
||||
** ^The [sqlite3_wal_hook()] function is used to register a callback that
|
||||
** will be invoked each time a database connection commits data to a
|
||||
** [write-ahead log] (i.e. whenever a transaction is committed in
|
||||
** [journal_mode | journal_mode=WAL mode]).
|
||||
**
|
||||
** ^The callback is invoked by SQLite after the commit has taken place and
|
||||
** the associated write-lock on the database released, so the implementation
|
||||
** may read, write or [checkpoint] the database as required.
|
||||
**
|
||||
** ^The first parameter passed to the callback function when it is invoked
|
||||
** is a copy of the third parameter passed to sqlite3_wal_hook() when
|
||||
** registering the callback. ^The second is a copy of the database handle.
|
||||
** ^The third parameter is the name of the database that was written to -
|
||||
** either "main" or the name of an ATTACHed database. ^The fourth parameter
|
||||
** is the number of pages currently in the write-ahead log file,
|
||||
** including those that were just committed.
|
||||
**
|
||||
** The callback function should normally return SQLITE_OK. ^If an error
|
||||
** code is returned, that error will propagate back up through the
|
||||
** SQLite code base to cause the statement that provoked the callback
|
||||
** to report an error, though the commit will have still occurred.
|
||||
**
|
||||
** A single database handle may have at most a single write-ahead log callback
|
||||
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
|
||||
** previously registered write-ahead log callback. Note that the
|
||||
** [sqlite3_wal_autocheckpoint()] interface and the
|
||||
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
|
||||
** those overwrite any prior [sqlite3_wal_hook()] settings.
|
||||
*/
|
||||
void *sqlite3_wal_hook(
|
||||
sqlite3*,
|
||||
int(*)(void *,sqlite3*,const char*,int),
|
||||
void*
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configure an auto-checkpoint
|
||||
**
|
||||
** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
|
||||
** [sqlite3_wal_hook()] that causes any database on [database connection] D
|
||||
** to automatically [checkpoint]
|
||||
** after committing a transaction if there are N or
|
||||
** more frames in the [write-ahead log] file. ^Passing zero or
|
||||
** a negative value as the nFrame parameter disables automatic
|
||||
** checkpoints entirely.
|
||||
**
|
||||
** ^The callback registered by this function replaces any existing callback
|
||||
** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback
|
||||
** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
|
||||
** configured by this function.
|
||||
**
|
||||
** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
|
||||
** from SQL.
|
||||
**
|
||||
** ^Every new [database connection] defaults to having the auto-checkpoint
|
||||
** enabled with a threshold of 1000 pages. The use of this interface
|
||||
** is only necessary if the default setting is found to be suboptimal
|
||||
** for a particular application.
|
||||
*/
|
||||
int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Checkpoint a database
|
||||
**
|
||||
** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
|
||||
** on [database connection] D to be [checkpointed]. ^If X is NULL or an
|
||||
** empty string, then a checkpoint is run on all databases of
|
||||
** connection D. ^If the database connection D is not in
|
||||
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
|
||||
**
|
||||
** ^The [wal_checkpoint pragma] can be used to invoke this interface
|
||||
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
|
||||
** [wal_autocheckpoint pragma] can be used to cause this interface to be
|
||||
** run whenever the WAL reaches a certain size threshold.
|
||||
*/
|
||||
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
** builds on processors without floating point support.
|
||||
|
||||
+61
-4
@@ -92,7 +92,7 @@
|
||||
** The correct "ANSI" way to do this is to use the intptr_t type.
|
||||
** Unfortunately, that typedef is not available on all compilers, or
|
||||
** if it is available, it requires an #include of specific headers
|
||||
** that very from one machine to the next.
|
||||
** that vary from one machine to the next.
|
||||
**
|
||||
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
|
||||
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
|
||||
@@ -301,6 +301,7 @@
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
# define double sqlite_int64
|
||||
# define float sqlite_int64
|
||||
# define LONGDOUBLE_TYPE sqlite_int64
|
||||
# ifndef SQLITE_BIG_DBL
|
||||
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
|
||||
@@ -822,6 +823,10 @@ struct sqlite3 {
|
||||
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
|
||||
void *pUpdateArg;
|
||||
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
int (*xWalCallback)(void *, sqlite3 *, const char *, int);
|
||||
void *pWalArg;
|
||||
#endif
|
||||
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
|
||||
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
|
||||
void *pCollNeededArg;
|
||||
@@ -911,6 +916,8 @@ struct sqlite3 {
|
||||
#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
|
||||
#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
|
||||
#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
|
||||
#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
|
||||
#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
|
||||
|
||||
/*
|
||||
** Bits of the sqlite3.flags field that are used by the
|
||||
@@ -922,7 +929,8 @@ struct sqlite3 {
|
||||
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
|
||||
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
|
||||
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
|
||||
#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
|
||||
#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
|
||||
#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
@@ -1773,6 +1781,9 @@ typedef u64 Bitmask;
|
||||
** and the next table on the list. The parser builds the list this way.
|
||||
** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
|
||||
** jointype expresses the join between the table and the previous table.
|
||||
**
|
||||
** In the colUsed field, the high-order bit (bit 63) is set if the table
|
||||
** contains more than 63 columns and the 64-th or later column is used.
|
||||
*/
|
||||
struct SrcList {
|
||||
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
@@ -1884,7 +1895,7 @@ struct WhereLevel {
|
||||
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
|
||||
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
|
||||
#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */
|
||||
#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
|
||||
#define WHERE_OMIT_OPEN 0x0010 /* Table cursors are already open */
|
||||
#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
|
||||
#define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */
|
||||
#define WHERE_ONETABLE_ONLY 0x0080 /* Only code the 1st table in pTabList */
|
||||
@@ -1907,6 +1918,7 @@ struct WhereInfo {
|
||||
int iBreak; /* Jump here to break out of the loop */
|
||||
int nLevel; /* Number of nested loop */
|
||||
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
|
||||
double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
|
||||
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
||||
};
|
||||
|
||||
@@ -2148,6 +2160,7 @@ struct Parse {
|
||||
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
|
||||
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
|
||||
u8 disableTriggers; /* True to disable triggers */
|
||||
double nQueryLoop; /* Estimated number of iterations of a query */
|
||||
|
||||
/* Above is constant between recursions. Below is reset before and after
|
||||
** each recursion */
|
||||
@@ -2524,6 +2537,7 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
|
||||
|
||||
#ifndef SQLITE_MUTEX_OMIT
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void);
|
||||
sqlite3_mutex_methods *sqlite3NoopMutex(void);
|
||||
sqlite3_mutex *sqlite3MutexAlloc(int);
|
||||
int sqlite3MutexInit(void);
|
||||
int sqlite3MutexEnd(void);
|
||||
@@ -2681,6 +2695,7 @@ void sqlite3Vacuum(Parse*);
|
||||
int sqlite3RunVacuum(char**, sqlite3*);
|
||||
char *sqlite3NameFromToken(sqlite3*, Token*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*);
|
||||
int sqlite3ExprListCompare(ExprList*, ExprList*);
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||
Vdbe *sqlite3GetVdbe(Parse*);
|
||||
@@ -2874,7 +2889,7 @@ extern int sqlite3PendingByte;
|
||||
#endif
|
||||
void sqlite3RootPageMoved(Db*, int, int);
|
||||
void sqlite3Reindex(Parse*, Token*, Token*);
|
||||
void sqlite3AlterFunctions(sqlite3*);
|
||||
void sqlite3AlterFunctions(void);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
int sqlite3GetToken(const unsigned char *, int *);
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
@@ -2983,6 +2998,9 @@ void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
|
||||
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
|
||||
int sqlite3TempInMemory(const sqlite3*);
|
||||
VTable *sqlite3GetVTable(sqlite3*, Table*);
|
||||
const char *sqlite3JournalModename(int);
|
||||
int sqlite3Checkpoint(sqlite3*, int);
|
||||
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
|
||||
|
||||
/* Declarations for functions in fkey.c. All of these are replaced by
|
||||
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
|
||||
@@ -3089,4 +3107,43 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
|
||||
# define sqlite3VdbeIOTraceSql(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** These routines are available for the mem2.c debugging memory allocator
|
||||
** only. They are used to verify that different "types" of memory
|
||||
** allocations are properly tracked by the system.
|
||||
**
|
||||
** sqlite3MemdebugSetType() sets the "type" of an allocation to one of
|
||||
** the MEMTYPE_* macros defined below. The type must be a bitmask with
|
||||
** a single bit set.
|
||||
**
|
||||
** sqlite3MemdebugHasType() returns true if any of the bits in its second
|
||||
** argument match the type set by the previous sqlite3MemdebugSetType().
|
||||
** sqlite3MemdebugHasType() is intended for use inside assert() statements.
|
||||
** For example:
|
||||
**
|
||||
** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
||||
**
|
||||
** Perhaps the most important point is the difference between MEMTYPE_HEAP
|
||||
** and MEMTYPE_DB. If an allocation is MEMTYPE_DB, that means it might have
|
||||
** been allocated by lookaside, except the allocation was too large or
|
||||
** lookaside was already full. It is important to verify that allocations
|
||||
** that might have been satisfied by lookaside are not passed back to
|
||||
** non-lookaside free() routines. Asserts such as the example above are
|
||||
** placed on the non-lookaside free() routines to verify this constraint.
|
||||
**
|
||||
** All of this is no-op for a production build. It only comes into
|
||||
** play when the SQLITE_MEMDEBUG compile-time option is used.
|
||||
*/
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
void sqlite3MemdebugSetType(void*,u8);
|
||||
int sqlite3MemdebugHasType(void*,u8);
|
||||
#else
|
||||
# define sqlite3MemdebugSetType(X,Y) /* no-op */
|
||||
# define sqlite3MemdebugHasType(X,Y) 1
|
||||
#endif
|
||||
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
|
||||
#define MEMTYPE_DB 0x02 /* Associated with a database connection */
|
||||
#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
|
||||
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
|
||||
|
||||
#endif /* _SQLITEINT_H_ */
|
||||
|
||||
@@ -108,6 +108,14 @@
|
||||
# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The default number of frames to accumulate in the log file before
|
||||
** checkpointing the database in WAL mode.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
|
||||
# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of attached databases. This must be between 0
|
||||
** and 30. The upper bound on 30 is because a 32-bit integer bitmap
|
||||
|
||||
@@ -112,6 +112,26 @@ int sqlite3_db_status(
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return an approximation for the amount of memory currently used
|
||||
** by all pagers associated with the given database connection. The
|
||||
** highwater mark is meaningless and is returned as zero.
|
||||
*/
|
||||
case SQLITE_DBSTATUS_CACHE_USED: {
|
||||
int totalUsed = 0;
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
Pager *pPager = sqlite3BtreePager(pBt);
|
||||
totalUsed += sqlite3PagerMemUsed(pPager);
|
||||
}
|
||||
}
|
||||
*pCurrent = totalUsed;
|
||||
*pHighwater = 0;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
+51
-5
@@ -123,6 +123,7 @@ struct SqliteDb {
|
||||
SqlFunc *pFunc; /* List of SQL functions */
|
||||
Tcl_Obj *pUpdateHook; /* Update hook script (if any) */
|
||||
Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
|
||||
Tcl_Obj *pWalHook; /* WAL hook script (if any) */
|
||||
Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */
|
||||
SqlCollate *pCollate; /* List of SQL collation functions */
|
||||
int rc; /* Return code of most recent sqlite3_exec() */
|
||||
@@ -132,7 +133,7 @@ struct SqliteDb {
|
||||
int maxStmt; /* The next maximum number of stmtList */
|
||||
int nStmt; /* Number of statements in stmtList */
|
||||
IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
|
||||
int nStep, nSort; /* Statistics for most recent operation */
|
||||
int nStep, nSort, nIndex; /* Statistics for most recent operation */
|
||||
int nTransaction; /* Number of nested [transaction] methods */
|
||||
};
|
||||
|
||||
@@ -485,6 +486,9 @@ static void DbDeleteCmd(void *db){
|
||||
if( pDb->pRollbackHook ){
|
||||
Tcl_DecrRefCount(pDb->pRollbackHook);
|
||||
}
|
||||
if( pDb->pWalHook ){
|
||||
Tcl_DecrRefCount(pDb->pWalHook);
|
||||
}
|
||||
if( pDb->pCollateNeeded ){
|
||||
Tcl_DecrRefCount(pDb->pCollateNeeded);
|
||||
}
|
||||
@@ -589,6 +593,35 @@ static void DbRollbackHandler(void *clientData){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This procedure handles wal_hook callbacks.
|
||||
*/
|
||||
static int DbWalHandler(
|
||||
void *clientData,
|
||||
sqlite3 *db,
|
||||
const char *zDb,
|
||||
int nEntry
|
||||
){
|
||||
int ret = SQLITE_OK;
|
||||
Tcl_Obj *p;
|
||||
SqliteDb *pDb = (SqliteDb*)clientData;
|
||||
Tcl_Interp *interp = pDb->interp;
|
||||
assert(pDb->pWalHook);
|
||||
|
||||
p = Tcl_DuplicateObj(pDb->pWalHook);
|
||||
Tcl_IncrRefCount(p);
|
||||
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
|
||||
Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
|
||||
if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|
||||
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
|
||||
){
|
||||
Tcl_BackgroundError(interp);
|
||||
}
|
||||
Tcl_DecrRefCount(p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
|
||||
static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){
|
||||
char zBuf[64];
|
||||
@@ -1351,6 +1384,7 @@ static int dbEvalStep(DbEvalContext *p){
|
||||
|
||||
pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1);
|
||||
pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1);
|
||||
pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1);
|
||||
dbReleaseColumnNames(p);
|
||||
p->pPreStmt = 0;
|
||||
|
||||
@@ -1544,7 +1578,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
"restore", "rollback_hook", "status",
|
||||
"timeout", "total_changes", "trace",
|
||||
"transaction", "unlock_notify", "update_hook",
|
||||
"version", 0
|
||||
"version", "wal_hook", 0
|
||||
};
|
||||
enum DB_enum {
|
||||
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
|
||||
@@ -1558,7 +1592,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS,
|
||||
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
|
||||
DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
|
||||
DB_VERSION,
|
||||
DB_VERSION, DB_WAL_HOOK
|
||||
};
|
||||
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||
|
||||
@@ -2528,7 +2562,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
|
||||
/*
|
||||
** $db status (step|sort)
|
||||
** $db status (step|sort|autoindex)
|
||||
**
|
||||
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
|
||||
** SQLITE_STMTSTATUS_SORT for the most recent eval.
|
||||
@@ -2545,8 +2579,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
v = pDb->nStep;
|
||||
}else if( strcmp(zOp, "sort")==0 ){
|
||||
v = pDb->nSort;
|
||||
}else if( strcmp(zOp, "autoindex")==0 ){
|
||||
v = pDb->nIndex;
|
||||
}else{
|
||||
Tcl_AppendResult(interp, "bad argument: should be step or sort",
|
||||
Tcl_AppendResult(interp,
|
||||
"bad argument: should be autoindex, step, or sort",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -2726,9 +2763,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
|
||||
/*
|
||||
** $db wal_hook ?script?
|
||||
** $db update_hook ?script?
|
||||
** $db rollback_hook ?script?
|
||||
*/
|
||||
case DB_WAL_HOOK:
|
||||
case DB_UPDATE_HOOK:
|
||||
case DB_ROLLBACK_HOOK: {
|
||||
|
||||
@@ -2738,6 +2777,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
Tcl_Obj **ppHook;
|
||||
if( choice==DB_UPDATE_HOOK ){
|
||||
ppHook = &pDb->pUpdateHook;
|
||||
}else if( choice==DB_WAL_HOOK ){
|
||||
ppHook = &pDb->pWalHook;
|
||||
}else{
|
||||
ppHook = &pDb->pRollbackHook;
|
||||
}
|
||||
@@ -2763,6 +2804,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
|
||||
sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb);
|
||||
sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb);
|
||||
sqlite3_wal_hook(pDb->db,(pDb->pWalHook?DbWalHandler:0),pDb);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -3477,6 +3519,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
extern int Sqlitetest9_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestasync_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
|
||||
extern int Sqlitetest_func_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_init_Init(Tcl_Interp*);
|
||||
@@ -3490,6 +3533,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
extern int SqlitetestOsinst_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestbackup_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestintarray_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestvfs_Init(Tcl_Interp *);
|
||||
|
||||
Sqliteconfig_Init(interp);
|
||||
Sqlitetest1_Init(interp);
|
||||
@@ -3503,6 +3547,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
Sqlitetest9_Init(interp);
|
||||
Sqlitetestasync_Init(interp);
|
||||
Sqlitetest_autoext_Init(interp);
|
||||
Sqlitetest_demovfs_Init(interp);
|
||||
Sqlitetest_func_Init(interp);
|
||||
Sqlitetest_hexio_Init(interp);
|
||||
Sqlitetest_init_Init(interp);
|
||||
@@ -3515,6 +3560,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
SqlitetestOsinst_Init(interp);
|
||||
Sqlitetestbackup_Init(interp);
|
||||
Sqlitetestintarray_Init(interp);
|
||||
Sqlitetestvfs_Init(interp);
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
Sqlitetestsse_Init(interp);
|
||||
|
||||
+31
@@ -2025,6 +2025,7 @@ static int test_stmt_status(
|
||||
} aOp[] = {
|
||||
{ "SQLITE_STMTSTATUS_FULLSCAN_STEP", SQLITE_STMTSTATUS_FULLSCAN_STEP },
|
||||
{ "SQLITE_STMTSTATUS_SORT", SQLITE_STMTSTATUS_SORT },
|
||||
{ "SQLITE_STMTSTATUS_AUTOINDEX", SQLITE_STMTSTATUS_AUTOINDEX },
|
||||
};
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "STMT PARAMETER RESETFLAG");
|
||||
@@ -4867,6 +4868,35 @@ static int test_unlock_notify(
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_wal_checkpoint db ?NAME?
|
||||
*/
|
||||
static int test_wal_checkpoint(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
char *zDb = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=3 && objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB ?NAME?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==3 ){
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
}
|
||||
rc = sqlite3_wal_checkpoint(db, zDb);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** tcl_objproc COMMANDNAME ARGS...
|
||||
@@ -5088,6 +5118,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
{ "sqlite3_unlock_notify", test_unlock_notify, 0 },
|
||||
#endif
|
||||
{ "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
|
||||
@@ -581,6 +581,7 @@ static int testPendingByte(
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" PENDING-BYTE\"", (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], &pbyte) ) return TCL_ERROR;
|
||||
rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
|
||||
|
||||
+36
-4
@@ -520,8 +520,31 @@ static int cfDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return g.iDeviceCharacteristics;
|
||||
}
|
||||
|
||||
/*
|
||||
** Pass-throughs for WAL support.
|
||||
*/
|
||||
static int cfShmOpen(sqlite3_file *pFile){
|
||||
return sqlite3OsShmOpen(((CrashFile*)pFile)->pRealFile);
|
||||
}
|
||||
static int cfShmSize(sqlite3_file *pFile, int reqSize, int *pNew){
|
||||
return sqlite3OsShmSize(((CrashFile*)pFile)->pRealFile, reqSize, pNew);
|
||||
}
|
||||
static int cfShmGet(sqlite3_file *pFile, int reqSize, int *pSize, void **pp){
|
||||
return sqlite3OsShmGet(((CrashFile*)pFile)->pRealFile, reqSize, pSize, pp);
|
||||
}
|
||||
static int cfShmRelease(sqlite3_file *pFile){
|
||||
return sqlite3OsShmRelease(((CrashFile*)pFile)->pRealFile);
|
||||
}
|
||||
static int cfShmLock(sqlite3_file *pFile, int desired, int *pGot){
|
||||
return sqlite3OsShmLock(((CrashFile*)pFile)->pRealFile, desired, pGot);
|
||||
}
|
||||
static int cfShmClose(sqlite3_file *pFile, int delFlag){
|
||||
return sqlite3OsShmClose(((CrashFile*)pFile)->pRealFile, delFlag);
|
||||
}
|
||||
|
||||
|
||||
static const sqlite3_io_methods CrashFileVtab = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
cfClose, /* xClose */
|
||||
cfRead, /* xRead */
|
||||
cfWrite, /* xWrite */
|
||||
@@ -533,7 +556,13 @@ static const sqlite3_io_methods CrashFileVtab = {
|
||||
cfCheckReservedLock, /* xCheckReservedLock */
|
||||
cfFileControl, /* xFileControl */
|
||||
cfSectorSize, /* xSectorSize */
|
||||
cfDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
cfDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
cfShmOpen, /* xShmOpen */
|
||||
cfShmSize, /* xShmSize */
|
||||
cfShmGet, /* xShmGet */
|
||||
cfShmRelease, /* xShmRelease */
|
||||
cfShmLock, /* xShmLock */
|
||||
cfShmClose /* xShmClose */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -764,7 +793,7 @@ static int crashEnableCmd(
|
||||
){
|
||||
int isEnable;
|
||||
static sqlite3_vfs crashVfs = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
0, /* szOsFile */
|
||||
0, /* mxPathname */
|
||||
0, /* pNext */
|
||||
@@ -781,7 +810,10 @@ static int crashEnableCmd(
|
||||
cfDlClose, /* xDlClose */
|
||||
cfRandomness, /* xRandomness */
|
||||
cfSleep, /* xSleep */
|
||||
cfCurrentTime /* xCurrentTime */
|
||||
cfCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetlastError */
|
||||
0, /* xRename */
|
||||
0, /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
if( objc!=2 ){
|
||||
|
||||
@@ -127,6 +127,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autoinc", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autoindex", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autoindex", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@@ -493,6 +499,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
|
||||
Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
Tcl_SetVar2(interp, "sqlite_options", "wal", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "wal", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_WSD
|
||||
Tcl_SetVar2(interp, "sqlite_options", "wsd", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
** 2010 April 7
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** An example of a simple VFS implementation that omits complex features
|
||||
** often not required or not possible on embedded platforms. Also includes
|
||||
** code to buffer writes to the journal file, which can be a significant
|
||||
** performance improvement on some embedded platforms.
|
||||
**
|
||||
*/
|
||||
|
||||
/*
|
||||
** OVERVIEW
|
||||
**
|
||||
** The code in this file implements a minimal SQLite VFS that can be
|
||||
** used on Linux and other posix-like operating systems. The following
|
||||
** system calls are used:
|
||||
**
|
||||
** File-system: access(), unlink(), getcwd()
|
||||
** File IO: open(), read(), write(), fsync(), close(), fstat()
|
||||
** Other: sleep(), usleep(), time()
|
||||
**
|
||||
** The following VFS features are omitted:
|
||||
**
|
||||
** 1. File locking. The user must ensure that there is at most one
|
||||
** connection to each database when using this VFS. Multiple
|
||||
** connections to a single shared-cache count as a single connection
|
||||
** for the purposes of the previous statement.
|
||||
**
|
||||
** 2. The loading of dynamic extensions (shared libraries).
|
||||
**
|
||||
** 3. Temporary files. The user must configure SQLite to use in-memory
|
||||
** temp files when using this VFS. The easiest way to do this is to
|
||||
** compile with:
|
||||
**
|
||||
** -DSQLITE_TEMP_STORE=3
|
||||
**
|
||||
** 4. File truncation. As of version 3.6.24, SQLite may run without
|
||||
** a working xTruncate() call, providing the user does not configure
|
||||
** SQLite to use "journal_mode=truncate", or use both
|
||||
** "journal_mode=persist" and ATTACHed databases.
|
||||
**
|
||||
** It is assumed that the system uses UNIX-like path-names. Specifically,
|
||||
** that '/' characters are used to separate path components and that
|
||||
** a path-name is a relative path unless it begins with a '/'. And that
|
||||
** no UTF-8 encoded paths are greater than 512 bytes in length.
|
||||
**
|
||||
** JOURNAL WRITE-BUFFERING
|
||||
**
|
||||
** To commit a transaction to the database, SQLite first writes rollback
|
||||
** information into the journal file. This usually consists of 4 steps:
|
||||
**
|
||||
** 1. The rollback information is sequentially written into the journal
|
||||
** file, starting at the start of the file.
|
||||
** 2. The journal file is synced to disk.
|
||||
** 3. A modification is made to the first few bytes of the journal file.
|
||||
** 4. The journal file is synced to disk again.
|
||||
**
|
||||
** Most of the data is written in step 1 using a series of calls to the
|
||||
** VFS xWrite() method. The buffers passed to the xWrite() calls are of
|
||||
** various sizes. For example, as of version 3.6.24, when committing a
|
||||
** transaction that modifies 3 pages of a database file that uses 4096
|
||||
** byte pages residing on a media with 512 byte sectors, SQLite makes
|
||||
** eleven calls to the xWrite() method to create the rollback journal,
|
||||
** as follows:
|
||||
**
|
||||
** Write offset | Bytes written
|
||||
** ----------------------------
|
||||
** 0 512
|
||||
** 512 4
|
||||
** 516 4096
|
||||
** 4612 4
|
||||
** 4616 4
|
||||
** 4620 4096
|
||||
** 8716 4
|
||||
** 8720 4
|
||||
** 8724 4096
|
||||
** 12820 4
|
||||
** ++++++++++++SYNC+++++++++++
|
||||
** 0 12
|
||||
** ++++++++++++SYNC+++++++++++
|
||||
**
|
||||
** On many operating systems, this is an efficient way to write to a file.
|
||||
** However, on some embedded systems that do not cache writes in OS
|
||||
** buffers it is much more efficient to write data in blocks that are
|
||||
** an integer multiple of the sector-size in size and aligned at the
|
||||
** start of a sector.
|
||||
**
|
||||
** To work around this, the code in this file allocates a fixed size
|
||||
** buffer of SQLITE_DEMOVFS_BUFFERSZ using sqlite3_malloc() whenever a
|
||||
** journal file is opened. It uses the buffer to coalesce sequential
|
||||
** writes into aligned SQLITE_DEMOVFS_BUFFERSZ blocks. When SQLite
|
||||
** invokes the xSync() method to sync the contents of the file to disk,
|
||||
** all accumulated data is written out, even if it does not constitute
|
||||
** a complete block. This means the actual IO to create the rollback
|
||||
** journal for the example transaction above is this:
|
||||
**
|
||||
** Write offset | Bytes written
|
||||
** ----------------------------
|
||||
** 0 8192
|
||||
** 8192 4632
|
||||
** ++++++++++++SYNC+++++++++++
|
||||
** 0 12
|
||||
** ++++++++++++SYNC+++++++++++
|
||||
**
|
||||
** Much more efficient if the underlying OS is not caching write
|
||||
** operations.
|
||||
*/
|
||||
|
||||
#if !defined(SQLITE_TEST) || defined(SQLITE_OS_UNIX)
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
** Size of the write buffer used by journal files in bytes.
|
||||
*/
|
||||
#ifndef SQLITE_DEMOVFS_BUFFERSZ
|
||||
# define SQLITE_DEMOVFS_BUFFERSZ 8192
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When using this VFS, the sqlite3_file* handles that SQLite uses are
|
||||
** actually pointers to instances of type DemoFile.
|
||||
*/
|
||||
typedef struct DemoFile DemoFile;
|
||||
struct DemoFile {
|
||||
sqlite3_file base; /* Base class. Must be first. */
|
||||
int fd; /* File descriptor */
|
||||
|
||||
char *aBuffer; /* Pointer to malloc'd buffer */
|
||||
int nBuffer; /* Valid bytes of data in zBuffer */
|
||||
sqlite3_int64 iBufferOfst; /* Offset in file of zBuffer[0] */
|
||||
};
|
||||
|
||||
/*
|
||||
** Write directly to the file passed as the first argument. Even if the
|
||||
** file has a write-buffer (DemoFile.aBuffer), ignore it.
|
||||
*/
|
||||
static int demoDirectWrite(
|
||||
DemoFile *p, /* File handle */
|
||||
const void *zBuf, /* Buffer containing data to write */
|
||||
int iAmt, /* Size of data to write in bytes */
|
||||
sqlite_int64 iOfst /* File offset to write to */
|
||||
){
|
||||
off_t ofst; /* Return value from lseek() */
|
||||
size_t nWrite; /* Return value from write() */
|
||||
|
||||
ofst = lseek(p->fd, iOfst, SEEK_SET);
|
||||
if( ofst!=iOfst ){
|
||||
return SQLITE_IOERR_WRITE;
|
||||
}
|
||||
|
||||
nWrite = write(p->fd, zBuf, iAmt);
|
||||
if( nWrite!=iAmt ){
|
||||
return SQLITE_IOERR_WRITE;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Flush the contents of the DemoFile.aBuffer buffer to disk. This is a
|
||||
** no-op if this particular file does not have a buffer (i.e. it is not
|
||||
** a journal file) or if the buffer is currently empty.
|
||||
*/
|
||||
static int demoFlushBuffer(DemoFile *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->nBuffer ){
|
||||
rc = demoDirectWrite(p, p->aBuffer, p->nBuffer, p->iBufferOfst);
|
||||
p->nBuffer = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a file.
|
||||
*/
|
||||
static int demoClose(sqlite3_file *pFile){
|
||||
int rc;
|
||||
DemoFile *p = (DemoFile*)pFile;
|
||||
rc = demoFlushBuffer(p);
|
||||
sqlite3_free(p->aBuffer);
|
||||
close(p->fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a file.
|
||||
*/
|
||||
static int demoRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
DemoFile *p = (DemoFile*)pFile;
|
||||
off_t ofst; /* Return value from lseek() */
|
||||
int nRead; /* Return value from read() */
|
||||
int rc; /* Return code from demoFlushBuffer() */
|
||||
|
||||
/* Flush any data in the write buffer to disk in case this operation
|
||||
** is trying to read data the file-region currently cached in the buffer.
|
||||
** It would be possible to detect this case and possibly save an
|
||||
** unnecessary write here, but in practice SQLite will rarely read from
|
||||
** a journal file when there is data cached in the write-buffer.
|
||||
*/
|
||||
rc = demoFlushBuffer(p);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
ofst = lseek(p->fd, iOfst, SEEK_SET);
|
||||
if( ofst!=iOfst ){
|
||||
return SQLITE_IOERR_READ;
|
||||
}
|
||||
nRead = read(p->fd, zBuf, iAmt);
|
||||
|
||||
if( nRead==iAmt ){
|
||||
return SQLITE_OK;
|
||||
}else if( nRead>=0 ){
|
||||
return SQLITE_IOERR_SHORT_READ;
|
||||
}
|
||||
|
||||
return SQLITE_IOERR_READ;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to a crash-file.
|
||||
*/
|
||||
static int demoWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
DemoFile *p = (DemoFile*)pFile;
|
||||
|
||||
if( p->aBuffer ){
|
||||
char *z = (char *)zBuf; /* Pointer to remaining data to write */
|
||||
int n = iAmt; /* Number of bytes at z */
|
||||
sqlite3_int64 i = iOfst; /* File offset to write to */
|
||||
|
||||
while( n>0 ){
|
||||
int nCopy; /* Number of bytes to copy into buffer */
|
||||
|
||||
/* If the buffer is full, or if this data is not being written directly
|
||||
** following the data already buffered, flush the buffer. Flushing
|
||||
** the buffer is a no-op if it is empty.
|
||||
*/
|
||||
if( p->nBuffer==SQLITE_DEMOVFS_BUFFERSZ || p->iBufferOfst+p->nBuffer!=i ){
|
||||
int rc = demoFlushBuffer(p);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
assert( p->nBuffer==0 || p->iBufferOfst+p->nBuffer==i );
|
||||
p->iBufferOfst = i - p->nBuffer;
|
||||
|
||||
/* Copy as much data as possible into the buffer. */
|
||||
nCopy = SQLITE_DEMOVFS_BUFFERSZ - p->nBuffer;
|
||||
if( nCopy>n ){
|
||||
nCopy = n;
|
||||
}
|
||||
memcpy(&p->aBuffer[p->nBuffer], z, nCopy);
|
||||
p->nBuffer += nCopy;
|
||||
|
||||
n -= nCopy;
|
||||
i += nCopy;
|
||||
z += nCopy;
|
||||
}
|
||||
}else{
|
||||
return demoDirectWrite(p, zBuf, iAmt, iOfst);
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate a file. This is a no-op for this VFS (see header comments at
|
||||
** the top of the file).
|
||||
*/
|
||||
static int demoTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
#if 0
|
||||
if( ftruncate(((DemoFile *)pFile)->fd, size) ) return SQLITE_IOERR_TRUNCATE;
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync the contents of the file to the persistent media.
|
||||
*/
|
||||
static int demoSync(sqlite3_file *pFile, int flags){
|
||||
DemoFile *p = (DemoFile*)pFile;
|
||||
int rc;
|
||||
|
||||
rc = demoFlushBuffer(p);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = fsync(p->fd);
|
||||
return (rc==0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write the size of the file in bytes to *pSize.
|
||||
*/
|
||||
static int demoFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
DemoFile *p = (DemoFile*)pFile;
|
||||
int rc; /* Return code from fstat() call */
|
||||
struct stat sStat; /* Output of fstat() call */
|
||||
|
||||
/* Flush the contents of the buffer to disk. As with the flush in the
|
||||
** demoRead() method, it would be possible to avoid this and save a write
|
||||
** here and there. But in practice this comes up so infrequently it is
|
||||
** not worth the trouble.
|
||||
*/
|
||||
rc = demoFlushBuffer(p);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = fstat(p->fd, &sStat);
|
||||
if( rc!=0 ) return SQLITE_IOERR_FSTAT;
|
||||
*pSize = sStat.st_size;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Locking functions. The xLock() and xUnlock() methods are both no-ops.
|
||||
** The xCheckReservedLock() always indicates that no other process holds
|
||||
** a reserved lock on the database file. This ensures that if a hot-journal
|
||||
** file is found in the file-system it is rolled back.
|
||||
*/
|
||||
static int demoLock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static int demoUnlock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static int demoCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
*pResOut = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** No xFileControl() verbs are implemented by this VFS.
|
||||
*/
|
||||
static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The xSectorSize() and xDeviceCharacteristics() methods. These two
|
||||
** may return special values allowing SQLite to optimize file-system
|
||||
** access to some extent. But it is also safe to simply return 0.
|
||||
*/
|
||||
static int demoSectorSize(sqlite3_file *pFile){
|
||||
return 0;
|
||||
}
|
||||
static int demoDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a file handle.
|
||||
*/
|
||||
static int demoOpen(
|
||||
sqlite3_vfs *pVfs, /* VFS */
|
||||
const char *zName, /* File to open, or 0 for a temp file */
|
||||
sqlite3_file *pFile, /* Pointer to DemoFile struct to populate */
|
||||
int flags, /* Input SQLITE_OPEN_XXX flags */
|
||||
int *pOutFlags /* Output SQLITE_OPEN_XXX flags (or NULL) */
|
||||
){
|
||||
static const sqlite3_io_methods demoio = {
|
||||
1, /* iVersion */
|
||||
demoClose, /* xClose */
|
||||
demoRead, /* xRead */
|
||||
demoWrite, /* xWrite */
|
||||
demoTruncate, /* xTruncate */
|
||||
demoSync, /* xSync */
|
||||
demoFileSize, /* xFileSize */
|
||||
demoLock, /* xLock */
|
||||
demoUnlock, /* xUnlock */
|
||||
demoCheckReservedLock, /* xCheckReservedLock */
|
||||
demoFileControl, /* xFileControl */
|
||||
demoSectorSize, /* xSectorSize */
|
||||
demoDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
};
|
||||
|
||||
DemoFile *p = (DemoFile*)pFile; /* Populate this structure */
|
||||
int oflags = 0; /* flags to pass to open() call */
|
||||
char *aBuf = 0;
|
||||
|
||||
if( zName==0 ){
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
|
||||
if( flags&SQLITE_OPEN_MAIN_JOURNAL ){
|
||||
aBuf = (char *)sqlite3_malloc(SQLITE_DEMOVFS_BUFFERSZ);
|
||||
if( !aBuf ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if( flags&SQLITE_OPEN_EXCLUSIVE ) oflags |= O_EXCL;
|
||||
if( flags&SQLITE_OPEN_CREATE ) oflags |= O_CREAT;
|
||||
if( flags&SQLITE_OPEN_READONLY ) oflags |= O_RDONLY;
|
||||
if( flags&SQLITE_OPEN_READWRITE ) oflags |= O_RDWR;
|
||||
|
||||
memset(p, 0, sizeof(DemoFile));
|
||||
p->fd = open(zName, oflags, 0600);
|
||||
if( p->fd<0 ){
|
||||
sqlite3_free(aBuf);
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
p->aBuffer = aBuf;
|
||||
|
||||
if( pOutFlags ){
|
||||
*pOutFlags = flags;
|
||||
}
|
||||
p->base.pMethods = &demoio;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the file identified by argument zPath. If the dirSync parameter
|
||||
** is non-zero, then ensure the file-system modification to delete the
|
||||
** file has been synced to disk before returning.
|
||||
*/
|
||||
static int demoDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
int rc;
|
||||
rc = unlink(zPath);
|
||||
if( rc==0 && dirSync ){
|
||||
int dfd; /* File descriptor open on directory */
|
||||
int i; /* Iterator variable */
|
||||
char zDir[pVfs->mxPathname+1];/* Name of directory containing file zPath */
|
||||
|
||||
/* Figure out the directory name from the path of the file deleted. */
|
||||
sqlite3_snprintf(pVfs->mxPathname, zDir, "%s", zPath);
|
||||
zDir[pVfs->mxPathname] = '\0';
|
||||
for(i=strlen(zDir); i>1 && zDir[i]!='/'; i++);
|
||||
zDir[i] = '\0';
|
||||
|
||||
/* Open a file-descriptor on the directory. Sync. Close. */
|
||||
dfd = open(zDir, O_RDONLY, 0);
|
||||
if( dfd<0 ){
|
||||
rc = -1;
|
||||
}else{
|
||||
rc = fsync(dfd);
|
||||
close(dfd);
|
||||
}
|
||||
}
|
||||
return (rc==0 ? SQLITE_OK : SQLITE_IOERR_DELETE);
|
||||
}
|
||||
|
||||
#ifndef F_OK
|
||||
# define F_OK 0
|
||||
#endif
|
||||
#ifndef R_OK
|
||||
# define R_OK 4
|
||||
#endif
|
||||
#ifndef W_OK
|
||||
# define W_OK 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Query the file-system to see if the named file exists, is readable or
|
||||
** is both readable and writable.
|
||||
*/
|
||||
static int demoAccess(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
int rc; /* access() return code */
|
||||
int eAccess = F_OK; /* Second argument to access() */
|
||||
|
||||
assert( flags==SQLITE_ACCESS_EXISTS /* access(zPath, F_OK) */
|
||||
|| flags==SQLITE_ACCESS_READ /* access(zPath, R_OK) */
|
||||
|| flags==SQLITE_ACCESS_READWRITE /* access(zPath, R_OK|W_OK) */
|
||||
);
|
||||
|
||||
if( flags==SQLITE_ACCESS_READWRITE ) eAccess = R_OK|W_OK;
|
||||
if( flags==SQLITE_ACCESS_READ ) eAccess = R_OK;
|
||||
|
||||
rc = access(zPath, eAccess);
|
||||
*pResOut = (rc==0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument zPath points to a nul-terminated string containing a file path.
|
||||
** If zPath is an absolute path, then it is copied as is into the output
|
||||
** buffer. Otherwise, if it is a relative path, then the equivalent full
|
||||
** path is written to the output buffer.
|
||||
**
|
||||
** This function assumes that paths are UNIX style. Specifically, that:
|
||||
**
|
||||
** 1. Path components are separated by a '/'. and
|
||||
** 2. Full paths begin with a '/' character.
|
||||
*/
|
||||
static int demoFullPathname(
|
||||
sqlite3_vfs *pVfs, /* VFS */
|
||||
const char *zPath, /* Input path (possibly a relative path) */
|
||||
int nPathOut, /* Size of output buffer in bytes */
|
||||
char *zPathOut /* Pointer to output buffer */
|
||||
){
|
||||
char zDir[pVfs->mxPathname+1];
|
||||
if( zPath[0]=='/' ){
|
||||
zDir[0] = '\0';
|
||||
}else{
|
||||
getcwd(zDir, sizeof(zDir));
|
||||
}
|
||||
zDir[pVfs->mxPathname] = '\0';
|
||||
|
||||
sqlite3_snprintf(nPathOut, zPathOut, "%s/%s", zDir, zPath);
|
||||
zPathOut[nPathOut-1] = '\0';
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following four VFS methods:
|
||||
**
|
||||
** xDlOpen
|
||||
** xDlError
|
||||
** xDlSym
|
||||
** xDlClose
|
||||
**
|
||||
** are supposed to implement the functionality needed by SQLite to load
|
||||
** extensions compiled as shared objects. This simple VFS does not support
|
||||
** this functionality, so the following functions are no-ops.
|
||||
*/
|
||||
static void *demoDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
return 0;
|
||||
}
|
||||
static void demoDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
||||
sqlite3_snprintf(nByte, zErrMsg, "Loadable extensions are not supported");
|
||||
zErrMsg[nByte-1] = '\0';
|
||||
}
|
||||
static void (*demoDlSym(sqlite3_vfs *pVfs, void *pH, const char *z))(void){
|
||||
return 0;
|
||||
}
|
||||
static void demoDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameter zByte points to a buffer nByte bytes in size. Populate this
|
||||
** buffer with pseudo-random data.
|
||||
*/
|
||||
static int demoRandomness(sqlite3_vfs *pVfs, int nByte, char *zByte){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sleep for at least nMicro microseconds. Return the (approximate) number
|
||||
** of microseconds slept for.
|
||||
*/
|
||||
static int demoSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
sleep(nMicro / 1000000);
|
||||
usleep(nMicro % 1000000);
|
||||
return nMicro;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set *pTime to the current UTC time expressed as a Julian day. Return
|
||||
** SQLITE_OK if successful, or an error code otherwise.
|
||||
**
|
||||
** http://en.wikipedia.org/wiki/Julian_day
|
||||
**
|
||||
** This implementation is not very good. The current time is rounded to
|
||||
** an integer number of seconds. Also, assuming time_t is a signed 32-bit
|
||||
** value, it will stop working some time in the year 2038 AD (the so-called
|
||||
** "year 2038" problem that afflicts systems that store time this way).
|
||||
*/
|
||||
static int demoCurrentTime(sqlite3_vfs *pVfs, double *pTime){
|
||||
time_t t = time(0);
|
||||
*pTime = t/86400.0 + 2440587.5;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function returns a pointer to the VFS implemented in this file.
|
||||
** To make the VFS available to SQLite:
|
||||
**
|
||||
** sqlite3_vfs_register(sqlite3_demovfs(), 0);
|
||||
*/
|
||||
sqlite3_vfs *sqlite3_demovfs(void){
|
||||
static sqlite3_vfs demovfs = {
|
||||
1, /* iVersion */
|
||||
sizeof(DemoFile), /* szOsFile */
|
||||
512, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"demo", /* zName */
|
||||
0, /* pAppData */
|
||||
demoOpen, /* xOpen */
|
||||
demoDelete, /* xDelete */
|
||||
demoAccess, /* xAccess */
|
||||
demoFullPathname, /* xFullPathname */
|
||||
demoDlOpen, /* xDlOpen */
|
||||
demoDlError, /* xDlError */
|
||||
demoDlSym, /* xDlSym */
|
||||
demoDlClose, /* xDlClose */
|
||||
demoRandomness, /* xRandomness */
|
||||
demoSleep, /* xSleep */
|
||||
demoCurrentTime, /* xCurrentTime */
|
||||
};
|
||||
return &demovfs;
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_TEST) || defined(SQLITE_OS_UNIX) */
|
||||
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
|
||||
#include <tcl.h>
|
||||
|
||||
#ifdef SQLITE_OS_UNIX
|
||||
static int register_demovfs(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_vfs_register(sqlite3_demovfs(), 1);
|
||||
return TCL_OK;
|
||||
}
|
||||
static int unregister_demovfs(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_vfs_unregister(sqlite3_demovfs());
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetest_demovfs_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "register_demovfs", register_demovfs, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "unregister_demovfs", unregister_demovfs, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
int Sqlitetest_demovfs_Init(Tcl_Interp *interp){ return TCL_OK; }
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_TEST */
|
||||
+55
-5
@@ -50,6 +50,12 @@ static int devsymCheckReservedLock(sqlite3_file*, int *);
|
||||
static int devsymFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int devsymSectorSize(sqlite3_file*);
|
||||
static int devsymDeviceCharacteristics(sqlite3_file*);
|
||||
static int devsymShmOpen(sqlite3_file*);
|
||||
static int devsymShmSize(sqlite3_file*,int,int*);
|
||||
static int devsymShmGet(sqlite3_file*,int,int*,void**);
|
||||
static int devsymShmRelease(sqlite3_file*);
|
||||
static int devsymShmLock(sqlite3_file*,int,int*);
|
||||
static int devsymShmClose(sqlite3_file*,int);
|
||||
|
||||
/*
|
||||
** Method declarations for devsym_vfs.
|
||||
@@ -69,7 +75,7 @@ static int devsymSleep(sqlite3_vfs*, int microseconds);
|
||||
static int devsymCurrentTime(sqlite3_vfs*, double*);
|
||||
|
||||
static sqlite3_vfs devsym_vfs = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
sizeof(devsym_file), /* szOsFile */
|
||||
DEVSYM_MAX_PATHNAME, /* mxPathname */
|
||||
0, /* pNext */
|
||||
@@ -92,11 +98,14 @@ static sqlite3_vfs devsym_vfs = {
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
devsymRandomness, /* xRandomness */
|
||||
devsymSleep, /* xSleep */
|
||||
devsymCurrentTime /* xCurrentTime */
|
||||
devsymCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetLastError */
|
||||
0, /* xRename */
|
||||
0 /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
static sqlite3_io_methods devsym_io_methods = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
devsymClose, /* xClose */
|
||||
devsymRead, /* xRead */
|
||||
devsymWrite, /* xWrite */
|
||||
@@ -108,7 +117,13 @@ static sqlite3_io_methods devsym_io_methods = {
|
||||
devsymCheckReservedLock, /* xCheckReservedLock */
|
||||
devsymFileControl, /* xFileControl */
|
||||
devsymSectorSize, /* xSectorSize */
|
||||
devsymDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
devsymShmOpen, /* xShmOpen */
|
||||
devsymShmSize, /* xShmSize */
|
||||
devsymShmGet, /* xShmGet */
|
||||
devsymShmRelease, /* xShmRelease */
|
||||
devsymShmLock, /* xShmLock */
|
||||
devsymShmClose /* xShmClose */
|
||||
};
|
||||
|
||||
struct DevsymGlobal {
|
||||
@@ -222,6 +237,36 @@ static int devsymDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return g.iDeviceChar;
|
||||
}
|
||||
|
||||
/*
|
||||
** Shared-memory methods are all pass-thrus.
|
||||
*/
|
||||
static int devsymShmOpen(sqlite3_file *pFile){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmOpen(p->pReal);
|
||||
}
|
||||
static int devsymShmSize(sqlite3_file *pFile, int reqSize, int *pSize){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmSize(p->pReal, reqSize, pSize);
|
||||
}
|
||||
static int devsymShmGet(sqlite3_file *pFile, int reqSz, int *pSize, void **pp){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmGet(p->pReal, reqSz, pSize, pp);
|
||||
}
|
||||
static int devsymShmRelease(sqlite3_file *pFile){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmRelease(p->pReal);
|
||||
}
|
||||
static int devsymShmLock(sqlite3_file *pFile, int desired, int *pGot){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmLock(p->pReal, desired, pGot);
|
||||
}
|
||||
static int devsymShmClose(sqlite3_file *pFile, int delFlag){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmClose(p->pReal, delFlag);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Open an devsym file handle.
|
||||
*/
|
||||
@@ -330,9 +375,10 @@ static int devsymSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
** Return the current time as a Julian Day number in *pTimeOut.
|
||||
*/
|
||||
static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return sqlite3OsCurrentTime(g.pVfs, pTimeOut);
|
||||
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This procedure registers the devsym vfs with SQLite. If the argument is
|
||||
** true, the devsym vfs becomes the new default vfs. It is the only publicly
|
||||
@@ -346,9 +392,13 @@ void devsym_register(int iDeviceChar, int iSectorSize){
|
||||
}
|
||||
if( iDeviceChar>=0 ){
|
||||
g.iDeviceChar = iDeviceChar;
|
||||
}else{
|
||||
g.iDeviceChar = 0;
|
||||
}
|
||||
if( iSectorSize>=0 ){
|
||||
g.iSectorSize = iSectorSize;
|
||||
}else{
|
||||
g.iSectorSize = 512;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -179,7 +179,7 @@ static sqlite3_vfs jt_vfs = {
|
||||
jtDlClose, /* xDlClose */
|
||||
jtRandomness, /* xRandomness */
|
||||
jtSleep, /* xSleep */
|
||||
jtCurrentTime /* xCurrentTime */
|
||||
jtCurrentTime, /* xCurrentTime */
|
||||
};
|
||||
|
||||
static sqlite3_io_methods jt_io_methods = {
|
||||
@@ -801,7 +801,7 @@ static int jtSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
** Return the current time as a Julian Day number in *pTimeOut.
|
||||
*/
|
||||
static int jtCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return sqlite3OsCurrentTime(g.pVfs, pTimeOut);
|
||||
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
||||
@@ -1287,6 +1287,7 @@ static int test_db_status(
|
||||
int op;
|
||||
} aOp[] = {
|
||||
{ "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
|
||||
{ "SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
|
||||
};
|
||||
Tcl_Obj *pResult;
|
||||
if( objc!=4 ){
|
||||
|
||||
+15
-3
@@ -198,7 +198,9 @@ static fs_vfs_t fs_vfs = {
|
||||
fsDlClose, /* xDlClose */
|
||||
fsRandomness, /* xRandomness */
|
||||
fsSleep, /* xSleep */
|
||||
fsCurrentTime /* xCurrentTime */
|
||||
fsCurrentTime, /* xCurrentTime */
|
||||
0, /* xRename */
|
||||
0 /* xCurrentTimeInt64 */
|
||||
},
|
||||
0, /* pFileList */
|
||||
0 /* pParent */
|
||||
@@ -217,7 +219,12 @@ static sqlite3_io_methods fs_io_methods = {
|
||||
fsCheckReservedLock, /* xCheckReservedLock */
|
||||
fsFileControl, /* xFileControl */
|
||||
fsSectorSize, /* xSectorSize */
|
||||
fsDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
fsDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
0, /* xShmOpen */
|
||||
0, /* xShmSize */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmClose */
|
||||
0, /* xShmDelete */
|
||||
};
|
||||
|
||||
|
||||
@@ -234,7 +241,12 @@ static sqlite3_io_methods tmp_io_methods = {
|
||||
tmpCheckReservedLock, /* xCheckReservedLock */
|
||||
tmpFileControl, /* xFileControl */
|
||||
tmpSectorSize, /* xSectorSize */
|
||||
tmpDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
tmpDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
0, /* xShmOpen */
|
||||
0, /* xShmSize */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmClose */
|
||||
0, /* xShmDelete */
|
||||
};
|
||||
|
||||
/* Useful macros used in several places */
|
||||
|
||||
+1
-1
@@ -203,7 +203,7 @@ static sqlite3_vfs inst_vfs = {
|
||||
instDlClose, /* xDlClose */
|
||||
instRandomness, /* xRandomness */
|
||||
instSleep, /* xSleep */
|
||||
instCurrentTime /* xCurrentTime */
|
||||
instCurrentTime, /* xCurrentTime */
|
||||
};
|
||||
|
||||
static sqlite3_io_methods inst_io_methods = {
|
||||
|
||||
@@ -58,6 +58,7 @@ static Tcl_ObjCmdProc blocking_step_proc;
|
||||
static Tcl_ObjCmdProc blocking_prepare_v2_proc;
|
||||
#endif
|
||||
int Sqlitetest1_Init(Tcl_Interp *);
|
||||
int Sqlite3_Init(Tcl_Interp *);
|
||||
|
||||
/* Functions from test1.c */
|
||||
void *sqlite3TestTextToPtr(const char *);
|
||||
@@ -124,6 +125,7 @@ static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
|
||||
#endif
|
||||
Sqlitetest1_Init(interp);
|
||||
Sqlitetest_mutex_Init(interp);
|
||||
Sqlite3_Init(interp);
|
||||
|
||||
rc = Tcl_Eval(interp, p->zScript);
|
||||
pRes = Tcl_GetObjResult(interp);
|
||||
|
||||
+808
@@ -0,0 +1,808 @@
|
||||
/*
|
||||
** 2010 May 05
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
*/
|
||||
#if SQLITE_TEST /* This file is used for testing only */
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "sqliteInt.h"
|
||||
|
||||
typedef struct Testvfs Testvfs;
|
||||
typedef struct TestvfsShm TestvfsShm;
|
||||
typedef struct TestvfsBuffer TestvfsBuffer;
|
||||
typedef struct TestvfsFile TestvfsFile;
|
||||
|
||||
/*
|
||||
** An open file handle.
|
||||
*/
|
||||
struct TestvfsFile {
|
||||
sqlite3_file base; /* Base class. Must be first */
|
||||
sqlite3_vfs *pVfs; /* The VFS */
|
||||
const char *zFilename; /* Filename as passed to xOpen() */
|
||||
sqlite3_file *pReal; /* The real, underlying file descriptor */
|
||||
Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */
|
||||
TestvfsBuffer *pShm; /* Shared memory buffer */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** An instance of this structure is allocated for each VFS created. The
|
||||
** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite
|
||||
** is set to point to it.
|
||||
*/
|
||||
struct Testvfs {
|
||||
char *zName; /* Name of this VFS */
|
||||
sqlite3_vfs *pParent; /* The VFS to use for file IO */
|
||||
sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
|
||||
Tcl_Interp *interp; /* Interpreter to run script in */
|
||||
int nScript; /* Number of elements in array apScript */
|
||||
Tcl_Obj **apScript; /* Script to execute */
|
||||
TestvfsBuffer *pBuffer; /* List of shared buffers */
|
||||
int isNoshm;
|
||||
};
|
||||
|
||||
/*
|
||||
** A shared-memory buffer.
|
||||
*/
|
||||
struct TestvfsBuffer {
|
||||
char *zFile; /* Associated file name */
|
||||
int n; /* Size of allocated buffer in bytes */
|
||||
u8 *a; /* Buffer allocated using ckalloc() */
|
||||
int nRef; /* Number of references to this object */
|
||||
TestvfsBuffer *pNext; /* Next in linked list of all buffers */
|
||||
};
|
||||
|
||||
|
||||
#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
|
||||
|
||||
|
||||
/*
|
||||
** Method declarations for TestvfsFile.
|
||||
*/
|
||||
static int tvfsClose(sqlite3_file*);
|
||||
static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
|
||||
static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size);
|
||||
static int tvfsSync(sqlite3_file*, int flags);
|
||||
static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
||||
static int tvfsLock(sqlite3_file*, int);
|
||||
static int tvfsUnlock(sqlite3_file*, int);
|
||||
static int tvfsCheckReservedLock(sqlite3_file*, int *);
|
||||
static int tvfsFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int tvfsSectorSize(sqlite3_file*);
|
||||
static int tvfsDeviceCharacteristics(sqlite3_file*);
|
||||
|
||||
/*
|
||||
** Method declarations for tvfs_vfs.
|
||||
*/
|
||||
static int tvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
||||
static int tvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
||||
static int tvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
||||
static int tvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
static void *tvfsDlOpen(sqlite3_vfs*, const char *zFilename);
|
||||
static void tvfsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
||||
static void (*tvfsDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
|
||||
static void tvfsDlClose(sqlite3_vfs*, void*);
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
static int tvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
static int tvfsSleep(sqlite3_vfs*, int microseconds);
|
||||
static int tvfsCurrentTime(sqlite3_vfs*, double*);
|
||||
|
||||
static int tvfsShmOpen(sqlite3_file*);
|
||||
static int tvfsShmSize(sqlite3_file*, int , int *);
|
||||
static int tvfsShmGet(sqlite3_file*, int , int *, void **);
|
||||
static int tvfsShmRelease(sqlite3_file*);
|
||||
static int tvfsShmLock(sqlite3_file*, int , int *);
|
||||
static int tvfsShmClose(sqlite3_file*, int);
|
||||
|
||||
static sqlite3_io_methods tvfs_io_methods = {
|
||||
2, /* iVersion */
|
||||
tvfsClose, /* xClose */
|
||||
tvfsRead, /* xRead */
|
||||
tvfsWrite, /* xWrite */
|
||||
tvfsTruncate, /* xTruncate */
|
||||
tvfsSync, /* xSync */
|
||||
tvfsFileSize, /* xFileSize */
|
||||
tvfsLock, /* xLock */
|
||||
tvfsUnlock, /* xUnlock */
|
||||
tvfsCheckReservedLock, /* xCheckReservedLock */
|
||||
tvfsFileControl, /* xFileControl */
|
||||
tvfsSectorSize, /* xSectorSize */
|
||||
tvfsDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
tvfsShmOpen, /* xShmOpen */
|
||||
tvfsShmSize, /* xShmSize */
|
||||
tvfsShmGet, /* xShmGet */
|
||||
tvfsShmRelease, /* xShmRelease */
|
||||
tvfsShmLock, /* xShmLock */
|
||||
tvfsShmClose /* xShmClose */
|
||||
};
|
||||
|
||||
/*
|
||||
** Close an tvfs-file.
|
||||
*/
|
||||
static int tvfsClose(sqlite3_file *pFile){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
if( p->pShmId ){
|
||||
Tcl_DecrRefCount(p->pShmId);
|
||||
p->pShmId = 0;
|
||||
}
|
||||
if( pFile->pMethods ){
|
||||
ckfree((char *)pFile->pMethods);
|
||||
}
|
||||
return sqlite3OsClose(p->pReal);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from an tvfs-file.
|
||||
*/
|
||||
static int tvfsRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to an tvfs-file.
|
||||
*/
|
||||
static int tvfsWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate an tvfs-file.
|
||||
*/
|
||||
static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsTruncate(p->pReal, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync an tvfs-file.
|
||||
*/
|
||||
static int tvfsSync(sqlite3_file *pFile, int flags){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsSync(p->pReal, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current file-size of an tvfs-file.
|
||||
*/
|
||||
static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsFileSize(p->pReal, pSize);
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock an tvfs-file.
|
||||
*/
|
||||
static int tvfsLock(sqlite3_file *pFile, int eLock){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsLock(p->pReal, eLock);
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock an tvfs-file.
|
||||
*/
|
||||
static int tvfsUnlock(sqlite3_file *pFile, int eLock){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsUnlock(p->pReal, eLock);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if another file-handle holds a RESERVED lock on an tvfs-file.
|
||||
*/
|
||||
static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsCheckReservedLock(p->pReal, pResOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** File control method. For custom operations on an tvfs-file.
|
||||
*/
|
||||
static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsFileControl(p->pReal, op, pArg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for an tvfs-file.
|
||||
*/
|
||||
static int tvfsSectorSize(sqlite3_file *pFile){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsSectorSize(p->pReal);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by an tvfs-file.
|
||||
*/
|
||||
static int tvfsDeviceCharacteristics(sqlite3_file *pFile){
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
return sqlite3OsDeviceCharacteristics(p->pReal);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open an tvfs file handle.
|
||||
*/
|
||||
static int tvfsOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
int rc;
|
||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
||||
p->pShm = 0;
|
||||
p->pShmId = 0;
|
||||
p->zFilename = zName;
|
||||
p->pVfs = pVfs;
|
||||
p->pReal = (sqlite3_file *)&p[1];
|
||||
rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, p->pReal, flags, pOutFlags);
|
||||
if( p->pReal->pMethods ){
|
||||
sqlite3_io_methods *pMethods;
|
||||
pMethods = (sqlite3_io_methods *)ckalloc(sizeof(sqlite3_io_methods));
|
||||
memcpy(pMethods, &tvfs_io_methods, sizeof(sqlite3_io_methods));
|
||||
if( ((Testvfs *)pVfs->pAppData)->isNoshm ){
|
||||
pMethods->xShmOpen = 0;
|
||||
pMethods->xShmGet = 0;
|
||||
pMethods->xShmSize = 0;
|
||||
pMethods->xShmRelease = 0;
|
||||
pMethods->xShmClose = 0;
|
||||
pMethods->xShmLock = 0;
|
||||
}
|
||||
pFile->pMethods = pMethods;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the file located at zPath. If the dirSync argument is true,
|
||||
** ensure the file-system modifications are synced to disk before
|
||||
** returning.
|
||||
*/
|
||||
static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
return sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);
|
||||
}
|
||||
|
||||
/*
|
||||
** Test for access permissions. Return true if the requested permission
|
||||
** is available, or false otherwise.
|
||||
*/
|
||||
static int tvfsAccess(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate buffer zOut with the full canonical pathname corresponding
|
||||
** to the pathname in zPath. zOut is guaranteed to point to a buffer
|
||||
** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
|
||||
*/
|
||||
static int tvfsFullPathname(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nOut,
|
||||
char *zOut
|
||||
){
|
||||
return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
/*
|
||||
** Open the dynamic library located at zPath and return a handle.
|
||||
*/
|
||||
static void *tvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
return sqlite3OsDlOpen(PARENTVFS(pVfs), zPath);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
|
||||
** utf-8 string describing the most recent error encountered associated
|
||||
** with dynamic libraries.
|
||||
*/
|
||||
static void tvfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
||||
sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
|
||||
*/
|
||||
static void (*tvfsDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
|
||||
return sqlite3OsDlSym(PARENTVFS(pVfs), p, zSym);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the dynamic library handle pHandle.
|
||||
*/
|
||||
static void tvfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
sqlite3OsDlClose(PARENTVFS(pVfs), pHandle);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
|
||||
/*
|
||||
** Populate the buffer pointed to by zBufOut with nByte bytes of
|
||||
** random data.
|
||||
*/
|
||||
static int tvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Sleep for nMicro microseconds. Return the number of microseconds
|
||||
** actually slept.
|
||||
*/
|
||||
static int tvfsSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
return sqlite3OsSleep(PARENTVFS(pVfs), nMicro);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current time as a Julian Day number in *pTimeOut.
|
||||
*/
|
||||
static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
|
||||
}
|
||||
|
||||
static void tvfsGrowBuffer(TestvfsFile *pFd, int reqSize, int *pNewSize){
|
||||
TestvfsBuffer *pBuffer = pFd->pShm;
|
||||
if( reqSize>pBuffer->n ){
|
||||
pBuffer->a = (u8 *)ckrealloc((char *)pBuffer->a, reqSize);
|
||||
memset(&pBuffer->a[pBuffer->n], 0x55, reqSize-pBuffer->n);
|
||||
pBuffer->n = reqSize;
|
||||
}
|
||||
*pNewSize = pBuffer->n;
|
||||
}
|
||||
|
||||
static void tvfsExecTcl(
|
||||
Testvfs *p,
|
||||
const char *zMethod,
|
||||
Tcl_Obj *arg1,
|
||||
Tcl_Obj *arg2,
|
||||
Tcl_Obj *arg3
|
||||
){
|
||||
int rc; /* Return code from Tcl_EvalObj() */
|
||||
int nArg; /* Elements in eval'd list */
|
||||
|
||||
p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1);
|
||||
p->apScript[p->nScript+1] = arg1;
|
||||
p->apScript[p->nScript+2] = arg2;
|
||||
p->apScript[p->nScript+3] = arg3;
|
||||
|
||||
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
|
||||
Tcl_IncrRefCount(p->apScript[nArg]);
|
||||
}
|
||||
|
||||
rc = Tcl_EvalObjv(p->interp, nArg, p->apScript, TCL_EVAL_GLOBAL);
|
||||
if( rc!=TCL_OK ){
|
||||
Tcl_BackgroundError(p->interp);
|
||||
Tcl_ResetResult(p->interp);
|
||||
}
|
||||
|
||||
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
|
||||
Tcl_DecrRefCount(p->apScript[nArg]);
|
||||
p->apScript[nArg] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int tvfsResultCode(Testvfs *p, int *pRc){
|
||||
struct errcode {
|
||||
int eCode;
|
||||
const char *zCode;
|
||||
} aCode[] = {
|
||||
{ SQLITE_OK, "SQLITE_OK" },
|
||||
{ SQLITE_ERROR, "SQLITE_ERROR" },
|
||||
{ SQLITE_IOERR, "SQLITE_IOERR" },
|
||||
{ SQLITE_LOCKED, "SQLITE_LOCKED" },
|
||||
{ SQLITE_BUSY, "SQLITE_BUSY" },
|
||||
};
|
||||
|
||||
const char *z;
|
||||
int i;
|
||||
|
||||
z = Tcl_GetStringResult(p->interp);
|
||||
for(i=0; i<ArraySize(aCode); i++){
|
||||
if( 0==strcmp(z, aCode[i].zCode) ){
|
||||
*pRc = aCode[i].eCode;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tvfsShmOpen(
|
||||
sqlite3_file *pFileDes
|
||||
){
|
||||
Testvfs *p;
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Tcl_Obj *pId = 0; /* Id for this connection */
|
||||
TestvfsBuffer *pBuffer; /* Buffer to open connection to */
|
||||
TestvfsFile *pFd; /* The testvfs file structure */
|
||||
|
||||
pFd = (TestvfsFile*)pFileDes;
|
||||
p = (Testvfs *)pFd->pVfs->pAppData;
|
||||
assert( pFd->pShmId==0 && pFd->pShm==0 );
|
||||
|
||||
/* Evaluate the Tcl script:
|
||||
**
|
||||
** SCRIPT xShmOpen FILENAME
|
||||
**
|
||||
** If the script returns an SQLite error code other than SQLITE_OK, an
|
||||
** error is returned to the caller. If it returns SQLITE_OK, the new
|
||||
** connection is named "anon". Otherwise, the value returned by the
|
||||
** script is used as the connection name.
|
||||
*/
|
||||
tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
|
||||
if( tvfsResultCode(p, &rc) ){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
pId = Tcl_NewStringObj("anon", -1);
|
||||
}else{
|
||||
pId = Tcl_GetObjResult(p->interp);
|
||||
}
|
||||
Tcl_IncrRefCount(pId);
|
||||
pFd->pShmId = pId;
|
||||
|
||||
/* Search for a TestvfsBuffer. Create a new one if required. */
|
||||
for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
|
||||
if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break;
|
||||
}
|
||||
if( !pBuffer ){
|
||||
int nByte = sizeof(TestvfsBuffer) + strlen(pFd->zFilename) + 1;
|
||||
pBuffer = (TestvfsBuffer *)ckalloc(nByte);
|
||||
memset(pBuffer, 0, nByte);
|
||||
pBuffer->zFile = (char *)&pBuffer[1];
|
||||
strcpy(pBuffer->zFile, pFd->zFilename);
|
||||
pBuffer->pNext = p->pBuffer;
|
||||
p->pBuffer = pBuffer;
|
||||
}
|
||||
|
||||
/* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */
|
||||
pBuffer->nRef++;
|
||||
pFd->pShm = pBuffer;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int tvfsShmSize(
|
||||
sqlite3_file *pFile,
|
||||
int reqSize,
|
||||
int *pNewSize
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||
|
||||
tvfsExecTcl(p, "xShmSize",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
tvfsGrowBuffer(pFd, reqSize, pNewSize);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tvfsShmGet(
|
||||
sqlite3_file *pFile,
|
||||
int reqMapSize,
|
||||
int *pMapSize,
|
||||
void **pp
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||
|
||||
tvfsExecTcl(p, "xShmGet",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
tvfsGrowBuffer(pFd, reqMapSize, pMapSize);
|
||||
*pp = pFd->pShm->a;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tvfsShmRelease(sqlite3_file *pFile){
|
||||
int rc = SQLITE_OK;
|
||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||
|
||||
tvfsExecTcl(p, "xShmRelease",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tvfsShmLock(
|
||||
sqlite3_file *pFile,
|
||||
int desiredLock,
|
||||
int *gotLock
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||
char *zLock = "";
|
||||
|
||||
switch( desiredLock ){
|
||||
case SQLITE_SHM_READ: zLock = "READ"; break;
|
||||
case SQLITE_SHM_WRITE: zLock = "WRITE"; break;
|
||||
case SQLITE_SHM_CHECKPOINT: zLock = "CHECKPOINT"; break;
|
||||
case SQLITE_SHM_RECOVER: zLock = "RECOVER"; break;
|
||||
case SQLITE_SHM_PENDING: zLock = "PENDING"; break;
|
||||
case SQLITE_SHM_UNLOCK: zLock = "UNLOCK"; break;
|
||||
}
|
||||
tvfsExecTcl(p, "xShmLock",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId,
|
||||
Tcl_NewStringObj(zLock, -1)
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
*gotLock = desiredLock;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tvfsShmClose(
|
||||
sqlite3_file *pFile,
|
||||
int deleteFlag
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||
TestvfsBuffer *pBuffer = pFd->pShm;
|
||||
|
||||
assert( pFd->pShmId && pFd->pShm );
|
||||
#if 0
|
||||
assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
|
||||
#endif
|
||||
|
||||
tvfsExecTcl(p, "xShmClose",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
|
||||
pBuffer->nRef--;
|
||||
if( pBuffer->nRef==0 ){
|
||||
TestvfsBuffer **pp;
|
||||
for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext));
|
||||
*pp = (*pp)->pNext;
|
||||
ckfree((char *)pBuffer->a);
|
||||
ckfree((char *)pBuffer);
|
||||
}
|
||||
Tcl_DecrRefCount(pFd->pShmId);
|
||||
pFd->pShmId = 0;
|
||||
pFd->pShm = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int testvfs_obj_cmd(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
Testvfs *p = (Testvfs *)cd;
|
||||
|
||||
static const char *CMD_strs[] = { "shm", "delete", 0 };
|
||||
enum DB_enum { CMD_SHM, CMD_DELETE };
|
||||
int i;
|
||||
|
||||
if( objc<2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIndexFromObj(interp, objv[1], CMD_strs, "subcommand", 0, &i) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
|
||||
switch( (enum DB_enum)i ){
|
||||
case CMD_SHM: {
|
||||
TestvfsBuffer *pBuffer;
|
||||
char *zName;
|
||||
if( objc!=3 && objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "FILE ?VALUE?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zName = Tcl_GetString(objv[2]);
|
||||
for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
|
||||
if( 0==strcmp(pBuffer->zFile, zName) ) break;
|
||||
}
|
||||
if( !pBuffer ){
|
||||
Tcl_AppendResult(interp, "no such file: ", zName, 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==4 ){
|
||||
int n;
|
||||
u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n);
|
||||
pBuffer->a = (u8 *)ckrealloc((char *)pBuffer->a, n);
|
||||
pBuffer->n = n;
|
||||
memcpy(pBuffer->a, a, n);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBuffer->a, pBuffer->n));
|
||||
break;
|
||||
}
|
||||
case CMD_DELETE: {
|
||||
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static void testvfs_obj_del(ClientData cd){
|
||||
int i;
|
||||
Testvfs *p = (Testvfs *)cd;
|
||||
for(i=0; i<p->nScript; i++){
|
||||
Tcl_DecrRefCount(p->apScript[i]);
|
||||
}
|
||||
sqlite3_vfs_unregister(p->pVfs);
|
||||
ckfree((char *)p->pVfs);
|
||||
ckfree((char *)p);
|
||||
}
|
||||
|
||||
#define TESTVFS_MAX_ARGS 12
|
||||
|
||||
/*
|
||||
** Usage: testvfs ?-noshm? VFSNAME SCRIPT
|
||||
**
|
||||
** This command creates two things when it is invoked: an SQLite VFS, and
|
||||
** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not
|
||||
** installed as the default VFS.
|
||||
**
|
||||
** The VFS passes all file I/O calls through to the underlying VFS.
|
||||
**
|
||||
** Whenever one of the xShmSize, xShmGet or xShmRelease methods of the VFS
|
||||
** are invoked, the SCRIPT is executed as follows:
|
||||
**
|
||||
** SCRIPT xShmSize FILENAME ID
|
||||
** SCRIPT xShmGet FILENAME ID
|
||||
** SCRIPT xShmRelease FILENAME ID
|
||||
**
|
||||
** The value returned by the invocation of SCRIPT above is interpreted as
|
||||
** an SQLite error code and returned to SQLite. Either a symbolic
|
||||
** "SQLITE_OK" or numeric "0" value may be returned.
|
||||
**
|
||||
** The contents of the shared-memory buffer associated with a given file
|
||||
** may be read and set using the following command:
|
||||
**
|
||||
** VFSNAME shm FILENAME ?NEWVALUE?
|
||||
**
|
||||
** When the xShmLock method is invoked by SQLite, the following script is
|
||||
** run:
|
||||
**
|
||||
** SCRIPT xShmLock FILENAME ID LOCK
|
||||
**
|
||||
** where LOCK is one of "UNLOCK", "READ", "READ_FULL", "WRITE", "PENDING",
|
||||
** "CHECKPOINT" or "RECOVER". The script should return an SQLite error
|
||||
** code.
|
||||
*/
|
||||
static int testvfs_cmd(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
static sqlite3_vfs tvfs_vfs = {
|
||||
2, /* iVersion */
|
||||
sizeof(TestvfsFile), /* szOsFile */
|
||||
0, /* mxPathname */
|
||||
0, /* pNext */
|
||||
0, /* zName */
|
||||
0, /* pAppData */
|
||||
tvfsOpen, /* xOpen */
|
||||
tvfsDelete, /* xDelete */
|
||||
tvfsAccess, /* xAccess */
|
||||
tvfsFullPathname, /* xFullPathname */
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
tvfsDlOpen, /* xDlOpen */
|
||||
tvfsDlError, /* xDlError */
|
||||
tvfsDlSym, /* xDlSym */
|
||||
tvfsDlClose, /* xDlClose */
|
||||
#else
|
||||
0, /* xDlOpen */
|
||||
0, /* xDlError */
|
||||
0, /* xDlSym */
|
||||
0, /* xDlClose */
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
tvfsRandomness, /* xRandomness */
|
||||
tvfsSleep, /* xSleep */
|
||||
tvfsCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetLastError */
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
Testvfs *p; /* New object */
|
||||
sqlite3_vfs *pVfs; /* New VFS */
|
||||
char *zVfs;
|
||||
Tcl_Obj *pScript;
|
||||
int nScript; /* Number of elements in list pScript */
|
||||
Tcl_Obj **apScript; /* Array of pScript elements */
|
||||
int nByte; /* Bytes of space to allocate at p */
|
||||
int i; /* Counter variable */
|
||||
int isNoshm = 0; /* True if -noshm is passed */
|
||||
|
||||
if( objc<3 ) goto bad_args;
|
||||
if( strcmp(Tcl_GetString(objv[1]), "-noshm")==0 ){
|
||||
isNoshm = 1;
|
||||
}
|
||||
if( objc!=3+isNoshm ) goto bad_args;
|
||||
zVfs = Tcl_GetString(objv[isNoshm+1]);
|
||||
pScript = objv[isNoshm+2];
|
||||
|
||||
if( TCL_OK!=Tcl_ListObjGetElements(interp, pScript, &nScript, &apScript) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
nByte = sizeof(Testvfs)
|
||||
+ (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *)
|
||||
+ strlen(zVfs)+1;
|
||||
p = (Testvfs *)ckalloc(nByte);
|
||||
memset(p, 0, nByte);
|
||||
|
||||
p->pParent = sqlite3_vfs_find(0);
|
||||
p->interp = interp;
|
||||
p->nScript = nScript;
|
||||
p->apScript = (Tcl_Obj **)&p[1];
|
||||
for(i=0; i<nScript; i++){
|
||||
p->apScript[i] = apScript[i];
|
||||
Tcl_IncrRefCount(p->apScript[i]);
|
||||
}
|
||||
p->zName = (char *)&p->apScript[nScript+TESTVFS_MAX_ARGS];
|
||||
strcpy(p->zName, zVfs);
|
||||
|
||||
pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs));
|
||||
memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs));
|
||||
pVfs->pAppData = (void *)p;
|
||||
pVfs->zName = p->zName;
|
||||
pVfs->mxPathname = p->pParent->mxPathname;
|
||||
pVfs->szOsFile += p->pParent->szOsFile;
|
||||
p->pVfs = pVfs;
|
||||
p->isNoshm = isNoshm;
|
||||
|
||||
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
|
||||
sqlite3_vfs_register(pVfs, 0);
|
||||
|
||||
return TCL_OK;
|
||||
|
||||
bad_args:
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
int Sqlitetestvfs_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -826,6 +826,7 @@ static TriggerPrg *codeRowTrigger(
|
||||
pSubParse->pToplevel = pTop;
|
||||
pSubParse->zAuthContext = pTrigger->zName;
|
||||
pSubParse->eTriggerOp = pTrigger->op;
|
||||
pSubParse->nQueryLoop = pParse->nQueryLoop;
|
||||
|
||||
v = sqlite3GetVdbe(pSubParse);
|
||||
if( v ){
|
||||
|
||||
+15
-4
@@ -103,7 +103,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
int isMemDb; /* True if vacuuming a :memory: database */
|
||||
int nRes;
|
||||
int nRes; /* Bytes of reserved space at the end of each page */
|
||||
int nDb; /* Number of attached databases */
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
|
||||
@@ -117,7 +118,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
saved_nChange = db->nChange;
|
||||
saved_nTotalChange = db->nTotalChange;
|
||||
saved_xTrace = db->xTrace;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
|
||||
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
|
||||
db->xTrace = 0;
|
||||
|
||||
@@ -138,15 +139,18 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** time to parse and run the PRAGMA to turn journalling off than it does
|
||||
** to write the journal header file.
|
||||
*/
|
||||
nDb = db->nDb;
|
||||
if( sqlite3TempInMemory(db) ){
|
||||
zSql = "ATTACH ':memory:' AS vacuum_db;";
|
||||
}else{
|
||||
zSql = "ATTACH '' AS vacuum_db;";
|
||||
}
|
||||
rc = execSql(db, pzErrMsg, zSql);
|
||||
if( db->nDb>nDb ){
|
||||
pDb = &db->aDb[db->nDb-1];
|
||||
assert( strcmp(pDb->zName,"vacuum_db")==0 );
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
pDb = &db->aDb[db->nDb-1];
|
||||
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
|
||||
pTemp = db->aDb[db->nDb-1].pBt;
|
||||
|
||||
/* The call to execSql() to attach the temp database has left the file
|
||||
@@ -168,6 +172,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do not attempt to change the page size for a WAL database */
|
||||
if( sqlite3PagerJournalMode(sqlite3BtreePager(pMain),
|
||||
PAGER_JOURNALMODE_QUERY)==PAGER_JOURNALMODE_WAL ){
|
||||
db->nextPagesize = 0;
|
||||
}
|
||||
|
||||
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|
||||
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|
||||
|| NEVER(db->mallocFailed)
|
||||
@@ -304,6 +314,7 @@ end_of_vacuum:
|
||||
db->nChange = saved_nChange;
|
||||
db->nTotalChange = saved_nTotalChange;
|
||||
db->xTrace = saved_xTrace;
|
||||
sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
|
||||
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
** database. No locks are held on any other files (since the main file
|
||||
|
||||
+170
-42
@@ -989,38 +989,23 @@ case OP_Blob: { /* out2-prerelease */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Variable P1 P2 P3 P4 *
|
||||
/* Opcode: Variable P1 P2 * P4 *
|
||||
**
|
||||
** Transfer the values of bound parameters P1..P1+P3-1 into registers
|
||||
** P2..P2+P3-1.
|
||||
** Transfer the values of bound parameter P1 into register P2
|
||||
**
|
||||
** If the parameter is named, then its name appears in P4 and P3==1.
|
||||
** The P4 value is used by sqlite3_bind_parameter_name().
|
||||
*/
|
||||
case OP_Variable: {
|
||||
int p1; /* Variable to copy from */
|
||||
int p2; /* Register to copy to */
|
||||
int n; /* Number of values left to copy */
|
||||
case OP_Variable: { /* out2-prerelease */
|
||||
Mem *pVar; /* Value being transferred */
|
||||
|
||||
p1 = pOp->p1 - 1;
|
||||
p2 = pOp->p2;
|
||||
n = pOp->p3;
|
||||
assert( p1>=0 && p1+n<=p->nVar );
|
||||
assert( p2>=1 && p2+n-1<=p->nMem );
|
||||
assert( pOp->p4.z==0 || pOp->p3==1 || pOp->p3==0 );
|
||||
|
||||
while( n-- > 0 ){
|
||||
pVar = &p->aVar[p1++];
|
||||
if( sqlite3VdbeMemTooBig(pVar) ){
|
||||
goto too_big;
|
||||
}
|
||||
pOut = &aMem[p2++];
|
||||
sqlite3VdbeMemReleaseExternal(pOut);
|
||||
pOut->flags = MEM_Null;
|
||||
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nVar );
|
||||
pVar = &p->aVar[pOp->p1 - 1];
|
||||
if( sqlite3VdbeMemTooBig(pVar) ){
|
||||
goto too_big;
|
||||
}
|
||||
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1383,7 +1368,7 @@ case OP_Function: {
|
||||
for(i=0; i<n; i++, pArg++){
|
||||
apVal[i] = pArg;
|
||||
sqlite3VdbeMemStoreType(pArg);
|
||||
REGISTER_TRACE(pOp->p2, pArg);
|
||||
REGISTER_TRACE(pOp->p2+i, pArg);
|
||||
}
|
||||
|
||||
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
|
||||
@@ -3068,10 +3053,10 @@ case OP_OpenWrite: {
|
||||
**
|
||||
** Open a new cursor P1 to a transient table.
|
||||
** The cursor is always opened read/write even if
|
||||
** the main database is read-only. The transient or virtual
|
||||
** the main database is read-only. The ephemeral
|
||||
** table is deleted automatically when the cursor is closed.
|
||||
**
|
||||
** P2 is the number of columns in the virtual table.
|
||||
** P2 is the number of columns in the ephemeral table.
|
||||
** The cursor points to a BTree table if P4==0 and to a BTree index
|
||||
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure
|
||||
** that defines the format of keys in the index.
|
||||
@@ -3082,6 +3067,14 @@ case OP_OpenWrite: {
|
||||
** this opcode. Then this opcode was call OpenVirtual. But
|
||||
** that created confusion with the whole virtual-table idea.
|
||||
*/
|
||||
/* Opcode: OpenAutoindex P1 P2 * P4 *
|
||||
**
|
||||
** This opcode works the same as OP_OpenEphemeral. It has a
|
||||
** different name to distinguish its use. Tables created using
|
||||
** by this opcode will be used for automatically created transient
|
||||
** indices in joins.
|
||||
*/
|
||||
case OP_OpenAutoindex:
|
||||
case OP_OpenEphemeral: {
|
||||
VdbeCursor *pCx;
|
||||
static const int openFlags =
|
||||
@@ -4190,7 +4183,7 @@ case OP_Rewind: { /* jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Next P1 P2 * * *
|
||||
/* Opcode: Next P1 P2 * * P5
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table or index. If there are no more key/value pairs then fall through
|
||||
@@ -4199,9 +4192,12 @@ case OP_Rewind: { /* jump */
|
||||
**
|
||||
** The P1 cursor must be for a real table, not a pseudo-table.
|
||||
**
|
||||
** If P5 is positive and the jump is taken, then event counter
|
||||
** number P5-1 in the prepared statement is incremented.
|
||||
**
|
||||
** See also: Prev
|
||||
*/
|
||||
/* Opcode: Prev P1 P2 * * *
|
||||
/* Opcode: Prev P1 P2 * * P5
|
||||
**
|
||||
** Back up cursor P1 so that it points to the previous key/data pair in its
|
||||
** table or index. If there is no previous key/value pairs then fall through
|
||||
@@ -4209,6 +4205,9 @@ case OP_Rewind: { /* jump */
|
||||
** jump immediately to P2.
|
||||
**
|
||||
** The P1 cursor must be for a real table, not a pseudo-table.
|
||||
**
|
||||
** If P5 is positive and the jump is taken, then event counter
|
||||
** number P5-1 in the prepared statement is incremented.
|
||||
*/
|
||||
case OP_Prev: /* jump */
|
||||
case OP_Next: { /* jump */
|
||||
@@ -4218,6 +4217,7 @@ case OP_Next: { /* jump */
|
||||
|
||||
CHECK_FOR_INTERRUPT;
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( pOp->p5<=ArraySize(p->aCounter) );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
if( pC==0 ){
|
||||
break; /* See ticket #2273 */
|
||||
@@ -5171,6 +5171,146 @@ case OP_AggFinal: {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/* Opcode: Checkpoint P1 * * * *
|
||||
**
|
||||
** Checkpoint database P1. This is a no-op if P1 is not currently in
|
||||
** WAL mode.
|
||||
*/
|
||||
case OP_Checkpoint: {
|
||||
rc = sqlite3Checkpoint(db, pOp->p1);
|
||||
break;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Opcode: JournalMode P1 P2 P3 * P5
|
||||
**
|
||||
** Change the journal mode of database P1 to P3. P3 must be one of the
|
||||
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
|
||||
** modes (delete, truncate, persist, off and memory), this is a simple
|
||||
** operation. No IO is required.
|
||||
**
|
||||
** If changing into or out of WAL mode the procedure is more complicated.
|
||||
**
|
||||
** Write a string containing the final journal-mode to register P2.
|
||||
**
|
||||
** If an attempt to change in to or out of WAL mode fails because another
|
||||
** connection also has the same database open, then an SQLITE_BUSY error
|
||||
** is raised if P5==0, or of P5!=0 the journal mode changed is skipped
|
||||
** without signaling the error.
|
||||
*/
|
||||
case OP_JournalMode: { /* out2-prerelease */
|
||||
Btree *pBt; /* Btree to change journal mode of */
|
||||
Pager *pPager; /* Pager associated with pBt */
|
||||
int eNew; /* New journal mode */
|
||||
int eOld; /* The old journal mode */
|
||||
const sqlite3_vfs *pVfs; /* The VFS of pPager */
|
||||
const char *zFilename; /* Name of database file for pPager */
|
||||
|
||||
eNew = pOp->p3;
|
||||
assert( eNew==PAGER_JOURNALMODE_DELETE
|
||||
|| eNew==PAGER_JOURNALMODE_TRUNCATE
|
||||
|| eNew==PAGER_JOURNALMODE_PERSIST
|
||||
|| eNew==PAGER_JOURNALMODE_OFF
|
||||
|| eNew==PAGER_JOURNALMODE_MEMORY
|
||||
|| eNew==PAGER_JOURNALMODE_WAL
|
||||
|| eNew==PAGER_JOURNALMODE_QUERY
|
||||
);
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
|
||||
/* This opcode is used in two places: PRAGMA journal_mode and ATTACH.
|
||||
** In PRAGMA journal_mode, the sqlite3VdbeUsesBtree() routine is called
|
||||
** when the statment is prepared and so p->aMutex.nMutex>0. All mutexes
|
||||
** are already acquired. But when used in ATTACH, sqlite3VdbeUsesBtree()
|
||||
** is not called when the statement is prepared because it requires the
|
||||
** iDb index of the database as a parameter, and the database has not
|
||||
** yet been attached so that index is unavailable. We have to wait
|
||||
** until runtime (now) to get the mutex on the newly attached database.
|
||||
** No other mutexes are required by the ATTACH command so this is safe
|
||||
** to do.
|
||||
*/
|
||||
assert( (p->btreeMask & (1<<pOp->p1))!=0 || p->aMutex.nMutex==0 );
|
||||
if( p->aMutex.nMutex==0 ){
|
||||
/* This occurs right after ATTACH. Get a mutex on the newly ATTACHed
|
||||
** database. */
|
||||
sqlite3VdbeUsesBtree(p, pOp->p1);
|
||||
sqlite3VdbeMutexArrayEnter(p);
|
||||
}
|
||||
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
pPager = sqlite3BtreePager(pBt);
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
zFilename = sqlite3PagerFilename(pPager);
|
||||
pVfs = sqlite3PagerVfs(pPager);
|
||||
|
||||
/* Do not allow a transition to journal_mode=WAL for a database
|
||||
** in temporary storage or if the VFS does not support xShmOpen.
|
||||
*/
|
||||
if( eNew==PAGER_JOURNALMODE_WAL
|
||||
&& (zFilename[0]==0 /* Temp file */
|
||||
|| !sqlite3PagerWalSupported(pPager)) /* No xShmOpen support */
|
||||
){
|
||||
eNew = PAGER_JOURNALMODE_QUERY;
|
||||
}
|
||||
|
||||
if( eNew!=PAGER_JOURNALMODE_QUERY ){
|
||||
eOld = sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_QUERY);
|
||||
if( (eNew!=eOld)
|
||||
&& (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL)
|
||||
){
|
||||
if( !db->autoCommit || db->activeVdbeCnt>1 ){
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3SetString(&p->zErrMsg, db,
|
||||
"cannot change %s wal mode from within a transaction",
|
||||
(eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
|
||||
);
|
||||
break;
|
||||
}else{
|
||||
|
||||
if( eOld==PAGER_JOURNALMODE_WAL ){
|
||||
/* If leaving WAL mode, close the log file. If successful, the call
|
||||
** to PagerCloseWal() checkpoints and deletes the write-ahead-log
|
||||
** file. An EXCLUSIVE lock may still be held on the database file
|
||||
** after a successful return.
|
||||
*/
|
||||
rc = sqlite3PagerCloseWal(pPager);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3PagerJournalMode(pPager, eNew);
|
||||
}else if( rc==SQLITE_BUSY && pOp->p5==0 ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
}else{
|
||||
sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Open a transaction on the database file. Regardless of the journal
|
||||
** mode, this transaction always uses a rollback journal.
|
||||
*/
|
||||
assert( sqlite3BtreeIsInTrans(pBt)==0 );
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeSetVersion(pBt,
|
||||
(eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
|
||||
if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error;
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
eNew = PAGER_JOURNALMODE_QUERY;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
||||
|
||||
eNew = sqlite3PagerJournalMode(pPager, eNew);
|
||||
pOut = &aMem[pOp->p2];
|
||||
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
|
||||
pOut->z = (char *)sqlite3JournalModename(eNew);
|
||||
pOut->n = sqlite3Strlen30(pOut->z);
|
||||
pOut->enc = SQLITE_UTF8;
|
||||
sqlite3VdbeChangeEncoding(pOut, encoding);
|
||||
break;
|
||||
};
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/* Opcode: Vacuum * * * * *
|
||||
@@ -5616,19 +5756,7 @@ case OP_VUpdate: {
|
||||
** Write the current number of pages in database P1 to memory cell P2.
|
||||
*/
|
||||
case OP_Pagecount: { /* out2-prerelease */
|
||||
int p1;
|
||||
int nPage;
|
||||
Pager *pPager;
|
||||
|
||||
p1 = pOp->p1;
|
||||
pPager = sqlite3BtreePager(db->aDb[p1].pBt);
|
||||
rc = sqlite3PagerPagecount(pPager, &nPage);
|
||||
/* OP_Pagecount is always called from within a read transaction. The
|
||||
** page count has already been successfully read and cached. So the
|
||||
** sqlite3PagerPagecount() call above cannot fail. */
|
||||
if( ALWAYS(rc==SQLITE_OK) ){
|
||||
pOut->u.i = nPage;
|
||||
}
|
||||
pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -311,7 +311,7 @@ struct Vdbe {
|
||||
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
||||
i64 startTime; /* Time when query started - used for profiling */
|
||||
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
|
||||
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
|
||||
int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
|
||||
char *zSql; /* Text of the SQL statement that generated this */
|
||||
void *pFree; /* Free this when deleting the vdbe */
|
||||
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
|
||||
|
||||
+39
-13
@@ -306,6 +306,27 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){
|
||||
pCtx->s.db->mallocFailed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called after a transaction has been committed. It
|
||||
** invokes callbacks registered with sqlite3_wal_hook() as required.
|
||||
*/
|
||||
static int doWalCallbacks(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
|
||||
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
|
||||
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute the statement pStmt, either until a row of data is ready, the
|
||||
** statement is completely executed or an error occurs.
|
||||
@@ -321,9 +342,12 @@ static int sqlite3Step(Vdbe *p){
|
||||
|
||||
assert(p);
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
"attempt to step a halted statement: [%s]", p->zSql);
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
/* We used to require that sqlite3_reset() be called before retrying
|
||||
** sqlite3_step() after any error. But after 3.6.23, we changed this
|
||||
** so that sqlite3_reset() would be called automatically instead of
|
||||
** throwing the error.
|
||||
*/
|
||||
sqlite3_reset((sqlite3_stmt*)p);
|
||||
}
|
||||
|
||||
/* Check that malloc() has not failed. If it has, return early. */
|
||||
@@ -351,9 +375,7 @@ static int sqlite3Step(Vdbe *p){
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( db->xProfile && !db->init.busy ){
|
||||
double rNow;
|
||||
sqlite3OsCurrentTime(db->pVfs, &rNow);
|
||||
p->startTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -374,16 +396,20 @@ static int sqlite3Step(Vdbe *p){
|
||||
/* Invoke the profile callback if there is one
|
||||
*/
|
||||
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
|
||||
double rNow;
|
||||
u64 elapseTime;
|
||||
|
||||
sqlite3OsCurrentTime(db->pVfs, &rNow);
|
||||
elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
|
||||
elapseTime -= p->startTime;
|
||||
db->xProfile(db->pProfileArg, p->zSql, elapseTime);
|
||||
sqlite3_int64 iNow;
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
|
||||
db->xProfile(db->pProfileArg, p->zSql, iNow - p->startTime);
|
||||
}
|
||||
#endif
|
||||
|
||||
if( rc==SQLITE_DONE ){
|
||||
assert( p->rc==SQLITE_OK );
|
||||
p->rc = doWalCallbacks(db);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
db->errCode = rc;
|
||||
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
|
||||
+7
-1
@@ -743,7 +743,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
||||
pOp->p4.pKeyInfo = pKeyInfo;
|
||||
if( pKeyInfo ){
|
||||
u8 *aSortOrder;
|
||||
memcpy(pKeyInfo, zP4, nByte);
|
||||
memcpy((char*)pKeyInfo, zP4, nByte - nField);
|
||||
aSortOrder = pKeyInfo->aSortOrder;
|
||||
if( aSortOrder ){
|
||||
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
|
||||
@@ -950,6 +950,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
|
||||
/*
|
||||
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
|
||||
**
|
||||
** The prepared statement has to know in advance which Btree objects
|
||||
** will be used so that it can acquire mutexes on them all in sorted
|
||||
** order (via sqlite3VdbeMutexArrayEnter(). Mutexes are acquired
|
||||
** in order (and released in reverse order) to avoid deadlocks.
|
||||
*/
|
||||
void sqlite3VdbeUsesBtree(Vdbe *p, int i){
|
||||
int mask;
|
||||
@@ -1449,6 +1454,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->cacheCtr = 1;
|
||||
p->minWriteFileFormat = 255;
|
||||
p->iStatement = 0;
|
||||
p->nFkConstraint = 0;
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -657,6 +657,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
}else{
|
||||
pParse->declareVtab = 1;
|
||||
pParse->db = db;
|
||||
pParse->nQueryLoop = 1;
|
||||
|
||||
if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
|
||||
&& pParse->pNewTable
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
** 2010 February 1
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface to the write-ahead logging
|
||||
** system. Refer to the comments below and the header comment attached to
|
||||
** the implementation of each function in log.c for further details.
|
||||
*/
|
||||
|
||||
#ifndef _WAL_H_
|
||||
#define _WAL_H_
|
||||
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
# define sqlite3WalOpen(x,y,z) 0
|
||||
# define sqlite3WalClose(w,x,y,z) 0
|
||||
# define sqlite3WalOpenSnapshot(y,z) 0
|
||||
# define sqlite3WalCloseSnapshot(z)
|
||||
# define sqlite3WalRead(v,w,x,y,z) 0
|
||||
# define sqlite3WalDbsize(y,z)
|
||||
# define sqlite3WalWriteLock(y,z) 0
|
||||
# define sqlite3WalUndo(x,y,z) 0
|
||||
# define sqlite3WalSavepoint(z) 0
|
||||
# define sqlite3WalSavepointUndo(y,z) 0
|
||||
# define sqlite3WalFrames(u,v,w,x,y,z) 0
|
||||
# define sqlite3WalCheckpoint(u,v,w,x,y,z) 0
|
||||
# define sqlite3WalCallback(z) 0
|
||||
#else
|
||||
|
||||
/* Connection to a write-ahead log (WAL) file.
|
||||
** There is one object of this type for each pager.
|
||||
*/
|
||||
typedef struct Wal Wal;
|
||||
|
||||
/* Open and close a connection to a write-ahead log. */
|
||||
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**);
|
||||
int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
|
||||
|
||||
/* Used by readers to open (lock) and close (unlock) a snapshot. A
|
||||
** snapshot is like a read-transaction. It is the state of the database
|
||||
** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
|
||||
** preserves the current state even if the other threads or processes
|
||||
** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
|
||||
** transaction and releases the lock.
|
||||
*/
|
||||
int sqlite3WalOpenSnapshot(Wal *pWal, int *);
|
||||
void sqlite3WalCloseSnapshot(Wal *pWal);
|
||||
|
||||
/* Read a page from the write-ahead log, if it is present. */
|
||||
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
|
||||
|
||||
/* Return the size of the database as it existed at the beginning
|
||||
** of the snapshot */
|
||||
void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno);
|
||||
|
||||
/* Obtain or release the WRITER lock. */
|
||||
int sqlite3WalWriteLock(Wal *pWal, int op);
|
||||
|
||||
/* Undo any frames written (but not committed) to the log */
|
||||
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
|
||||
|
||||
/* Return an integer that records the current (uncommitted) write
|
||||
** position in the WAL */
|
||||
u32 sqlite3WalSavepoint(Wal *pWal);
|
||||
|
||||
/* Move the write position of the WAL back to iFrame. Called in
|
||||
** response to a ROLLBACK TO command. */
|
||||
int sqlite3WalSavepointUndo(Wal *pWal, u32 iFrame);
|
||||
|
||||
/* Write a frame or frames to the log. */
|
||||
int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
|
||||
|
||||
/* Copy pages from the log to the database file */
|
||||
int sqlite3WalCheckpoint(
|
||||
Wal *pWal, /* Write-ahead log connection */
|
||||
int sync_flags, /* Flags to sync db file with (or 0) */
|
||||
int nBuf, /* Size of buffer nBuf */
|
||||
u8 *zBuf, /* Temporary buffer to use */
|
||||
int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
|
||||
void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
|
||||
);
|
||||
|
||||
/* Return the value to pass to a sqlite3_wal_hook callback, the
|
||||
** number of frames in the WAL at the point of the last commit since
|
||||
** sqlite3WalCallback() was called. If no commits have occurred since
|
||||
** the last call, then return 0.
|
||||
*/
|
||||
int sqlite3WalCallback(Wal *pWal);
|
||||
|
||||
/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
|
||||
** by the pager layer on the database file.
|
||||
*/
|
||||
int sqlite3WalExclusiveMode(Wal *pWal, int op);
|
||||
|
||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
||||
#endif /* _WAL_H_ */
|
||||
+413
-43
@@ -235,6 +235,7 @@ struct WhereCost {
|
||||
#define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */
|
||||
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
|
||||
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
|
||||
#define WHERE_NOT_FULLSCAN 0x000f3000 /* Does not do a full table scan */
|
||||
#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */
|
||||
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
|
||||
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
|
||||
@@ -244,6 +245,7 @@ struct WhereCost {
|
||||
#define WHERE_UNIQUE 0x04000000 /* Selects no more than one row */
|
||||
#define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
|
||||
#define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
|
||||
#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
|
||||
|
||||
/*
|
||||
** Initialize a preallocated WhereClause structure.
|
||||
@@ -1573,6 +1575,11 @@ static void bestOrClauseIndex(
|
||||
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
|
||||
WhereTerm *pTerm; /* A single term of the WHERE clause */
|
||||
|
||||
/* No OR-clause optimization allowed if the NOT INDEXED clause is used */
|
||||
if( pSrc->notIndexed ){
|
||||
return;
|
||||
}
|
||||
|
||||
/* Search the WHERE clause terms for a usable WO_OR term. */
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
||||
if( pTerm->eOperator==WO_OR
|
||||
@@ -1615,8 +1622,9 @@ static void bestOrClauseIndex(
|
||||
/* If there is an ORDER BY clause, increase the scan cost to account
|
||||
** for the cost of the sort. */
|
||||
if( pOrderBy!=0 ){
|
||||
WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
|
||||
rTotal, rTotal+nRow*estLog(nRow)));
|
||||
rTotal += nRow*estLog(nRow);
|
||||
WHERETRACE(("... sorting increases OR cost to %.9g\n", rTotal));
|
||||
}
|
||||
|
||||
/* If the cost of scanning using this OR term for optimization is
|
||||
@@ -1635,6 +1643,247 @@ static void bestOrClauseIndex(
|
||||
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
/*
|
||||
** Return TRUE if the WHERE clause term pTerm is of a form where it
|
||||
** could be used with an index to access pSrc, assuming an appropriate
|
||||
** index existed.
|
||||
*/
|
||||
static int termCanDriveIndex(
|
||||
WhereTerm *pTerm, /* WHERE clause term to check */
|
||||
struct SrcList_item *pSrc, /* Table we are trying to access */
|
||||
Bitmask notReady /* Tables in outer loops of the join */
|
||||
){
|
||||
char aff;
|
||||
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
|
||||
if( pTerm->eOperator!=WO_EQ ) return 0;
|
||||
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
|
||||
aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
|
||||
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
/*
|
||||
** If the query plan for pSrc specified in pCost is a full table scan
|
||||
** and indexing is allows (if there is no NOT INDEXED clause) and it
|
||||
** possible to construct a transient index that would perform better
|
||||
** than a full table scan even when the cost of constructing the index
|
||||
** is taken into account, then alter the query plan to use the
|
||||
** transient index.
|
||||
*/
|
||||
static void bestAutomaticIndex(
|
||||
Parse *pParse, /* The parsing context */
|
||||
WhereClause *pWC, /* The WHERE clause */
|
||||
struct SrcList_item *pSrc, /* The FROM clause term to search */
|
||||
Bitmask notReady, /* Mask of cursors that are not available */
|
||||
WhereCost *pCost /* Lowest cost query plan */
|
||||
){
|
||||
double nTableRow; /* Rows in the input table */
|
||||
double logN; /* log(nTableRow) */
|
||||
double costTempIdx; /* per-query cost of the transient index */
|
||||
WhereTerm *pTerm; /* A single term of the WHERE clause */
|
||||
WhereTerm *pWCEnd; /* End of pWC->a[] */
|
||||
Table *pTable; /* Table tht might be indexed */
|
||||
|
||||
if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){
|
||||
/* Automatic indices are disabled at run-time */
|
||||
return;
|
||||
}
|
||||
if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
|
||||
/* We already have some kind of index in use for this query. */
|
||||
return;
|
||||
}
|
||||
if( pSrc->notIndexed ){
|
||||
/* The NOT INDEXED clause appears in the SQL. */
|
||||
return;
|
||||
}
|
||||
|
||||
assert( pParse->nQueryLoop >= (double)1 );
|
||||
pTable = pSrc->pTab;
|
||||
nTableRow = pTable->pIndex ? pTable->pIndex->aiRowEst[0] : 1000000;
|
||||
logN = estLog(nTableRow);
|
||||
costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
|
||||
if( costTempIdx>=pCost->rCost ){
|
||||
/* The cost of creating the transient table would be greater than
|
||||
** doing the full table scan */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Search for any equality comparison term */
|
||||
pWCEnd = &pWC->a[pWC->nTerm];
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
||||
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
||||
WHERETRACE(("auto-index reduces cost from %.2f to %.2f\n",
|
||||
pCost->rCost, costTempIdx));
|
||||
pCost->rCost = costTempIdx;
|
||||
pCost->nRow = logN + 1;
|
||||
pCost->plan.wsFlags = WHERE_TEMP_INDEX;
|
||||
pCost->used = pTerm->prereqRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
|
||||
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
/*
|
||||
** Generate code to construct the Index object for an automatic index
|
||||
** and to set up the WhereLevel object pLevel so that the code generator
|
||||
** makes use of the automatic index.
|
||||
*/
|
||||
static void constructAutomaticIndex(
|
||||
Parse *pParse, /* The parsing context */
|
||||
WhereClause *pWC, /* The WHERE clause */
|
||||
struct SrcList_item *pSrc, /* The FROM clause term to get the next index */
|
||||
Bitmask notReady, /* Mask of cursors that are not available */
|
||||
WhereLevel *pLevel /* Write new index here */
|
||||
){
|
||||
int nColumn; /* Number of columns in the constructed index */
|
||||
WhereTerm *pTerm; /* A single term of the WHERE clause */
|
||||
WhereTerm *pWCEnd; /* End of pWC->a[] */
|
||||
int nByte; /* Byte of memory needed for pIdx */
|
||||
Index *pIdx; /* Object describing the transient index */
|
||||
Vdbe *v; /* Prepared statement under construction */
|
||||
int regIsInit; /* Register set by initialization */
|
||||
int addrInit; /* Address of the initialization bypass jump */
|
||||
Table *pTable; /* The table being indexed */
|
||||
KeyInfo *pKeyinfo; /* Key information for the index */
|
||||
int addrTop; /* Top of the index fill loop */
|
||||
int regRecord; /* Register holding an index record */
|
||||
int n; /* Column counter */
|
||||
int i; /* Loop counter */
|
||||
int mxBitCol; /* Maximum column in pSrc->colUsed */
|
||||
CollSeq *pColl; /* Collating sequence to on a column */
|
||||
Bitmask idxCols; /* Bitmap of columns used for indexing */
|
||||
Bitmask extraCols; /* Bitmap of additional columns */
|
||||
|
||||
/* Generate code to skip over the creation and initialization of the
|
||||
** transient index on 2nd and subsequent iterations of the loop. */
|
||||
v = pParse->pVdbe;
|
||||
assert( v!=0 );
|
||||
regIsInit = ++pParse->nMem;
|
||||
addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit);
|
||||
|
||||
/* Count the number of columns that will be added to the index
|
||||
** and used to match WHERE clause constraints */
|
||||
nColumn = 0;
|
||||
pTable = pSrc->pTab;
|
||||
pWCEnd = &pWC->a[pWC->nTerm];
|
||||
idxCols = 0;
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
||||
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
||||
int iCol = pTerm->u.leftColumn;
|
||||
Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
|
||||
testcase( iCol==BMS );
|
||||
testcase( iCol==BMS-1 );
|
||||
if( (idxCols & cMask)==0 ){
|
||||
nColumn++;
|
||||
idxCols |= cMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( nColumn>0 );
|
||||
pLevel->plan.nEq = nColumn;
|
||||
|
||||
/* Count the number of additional columns needed to create a
|
||||
** covering index. A "covering index" is an index that contains all
|
||||
** columns that are needed by the query. With a covering index, the
|
||||
** original table never needs to be accessed. Automatic indices must
|
||||
** be a covering index because the index will not be updated if the
|
||||
** original table changes and the index and table cannot both be used
|
||||
** if they go out of sync.
|
||||
*/
|
||||
extraCols = pSrc->colUsed & (~idxCols | (((Bitmask)1)<<(BMS-1)));
|
||||
mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
|
||||
testcase( pTable->nCol==BMS-1 );
|
||||
testcase( pTable->nCol==BMS-2 );
|
||||
for(i=0; i<mxBitCol; i++){
|
||||
if( extraCols & (((Bitmask)1)<<i) ) nColumn++;
|
||||
}
|
||||
if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
|
||||
nColumn += pTable->nCol - BMS + 1;
|
||||
}
|
||||
pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WO_EQ;
|
||||
|
||||
/* Construct the Index object to describe this index */
|
||||
nByte = sizeof(Index);
|
||||
nByte += nColumn*sizeof(int); /* Index.aiColumn */
|
||||
nByte += nColumn*sizeof(char*); /* Index.azColl */
|
||||
nByte += nColumn; /* Index.aSortOrder */
|
||||
pIdx = sqlite3DbMallocZero(pParse->db, nByte);
|
||||
if( pIdx==0 ) return;
|
||||
pLevel->plan.u.pIdx = pIdx;
|
||||
pIdx->azColl = (char**)&pIdx[1];
|
||||
pIdx->aiColumn = (int*)&pIdx->azColl[nColumn];
|
||||
pIdx->aSortOrder = (u8*)&pIdx->aiColumn[nColumn];
|
||||
pIdx->zName = "auto-index";
|
||||
pIdx->nColumn = nColumn;
|
||||
pIdx->pTable = pTable;
|
||||
n = 0;
|
||||
idxCols = 0;
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
||||
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
||||
int iCol = pTerm->u.leftColumn;
|
||||
Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
|
||||
if( (idxCols & cMask)==0 ){
|
||||
Expr *pX = pTerm->pExpr;
|
||||
idxCols |= cMask;
|
||||
pIdx->aiColumn[n] = pTerm->u.leftColumn;
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
|
||||
pIdx->azColl[n] = pColl->zName;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( n==pLevel->plan.nEq );
|
||||
|
||||
/* Add additional columns needed to make the automatic index into
|
||||
** a covering index */
|
||||
for(i=0; i<mxBitCol; i++){
|
||||
if( extraCols & (((Bitmask)1)<<i) ){
|
||||
pIdx->aiColumn[n] = i;
|
||||
pIdx->azColl[n] = "BINARY";
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
|
||||
for(i=BMS-1; i<pTable->nCol; i++){
|
||||
pIdx->aiColumn[n] = i;
|
||||
pIdx->azColl[n] = "BINARY";
|
||||
n++;
|
||||
}
|
||||
}
|
||||
assert( n==nColumn );
|
||||
|
||||
/* Create the automatic index */
|
||||
pKeyinfo = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
assert( pLevel->iIdxCur>=0 );
|
||||
sqlite3VdbeAddOp4(v, OP_OpenAutoindex, pLevel->iIdxCur, nColumn+1, 0,
|
||||
(char*)pKeyinfo, P4_KEYINFO_HANDOFF);
|
||||
VdbeComment((v, "for %s", pTable->zName));
|
||||
|
||||
/* Fill the automatic index with content */
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
|
||||
sqlite3VdbeJumpHere(v, addrTop);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
|
||||
/* Jump here when skipping the initialization */
|
||||
sqlite3VdbeJumpHere(v, addrInit);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Allocate and populate an sqlite3_index_info structure. It is the
|
||||
@@ -1819,6 +2068,7 @@ static void bestVirtualIndex(
|
||||
WhereTerm *pTerm;
|
||||
int i, j;
|
||||
int nOrderBy;
|
||||
double rCost;
|
||||
|
||||
/* Make sure wsFlags is initialized to some sane value. Otherwise, if the
|
||||
** malloc in allocateIndexInfo() fails and this function returns leaving
|
||||
@@ -1905,6 +2155,15 @@ static void bestVirtualIndex(
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is an ORDER BY clause, and the selected virtual table index
|
||||
** does not satisfy it, increase the cost of the scan accordingly. This
|
||||
** matches the processing for non-virtual tables in bestBtreeIndex().
|
||||
*/
|
||||
rCost = pIdxInfo->estimatedCost;
|
||||
if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
|
||||
rCost += estLog(rCost)*rCost;
|
||||
}
|
||||
|
||||
/* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
|
||||
** inital value of lowestCost in this loop. If it is, then the
|
||||
** (cost<lowestCost) test below will never be true.
|
||||
@@ -1912,10 +2171,10 @@ static void bestVirtualIndex(
|
||||
** Use "(double)2" instead of "2.0" in case OMIT_FLOATING_POINT
|
||||
** is defined.
|
||||
*/
|
||||
if( (SQLITE_BIG_DBL/((double)2))<pIdxInfo->estimatedCost ){
|
||||
if( (SQLITE_BIG_DBL/((double)2))<rCost ){
|
||||
pCost->rCost = (SQLITE_BIG_DBL/((double)2));
|
||||
}else{
|
||||
pCost->rCost = pIdxInfo->estimatedCost;
|
||||
pCost->rCost = rCost;
|
||||
}
|
||||
pCost->plan.u.pVtabIdx = pIdxInfo;
|
||||
if( pIdxInfo->orderByConsumed ){
|
||||
@@ -2316,14 +2575,14 @@ static void bestBtreeIndex(
|
||||
** Set to true if there was at least one "x IN (SELECT ...)" term used
|
||||
** in determining the value of nInMul.
|
||||
**
|
||||
** nBound:
|
||||
** estBound:
|
||||
** An estimate on the amount of the table that must be searched. A
|
||||
** value of 100 means the entire table is searched. Range constraints
|
||||
** might reduce this to a value less than 100 to indicate that only
|
||||
** a fraction of the table needs searching. In the absence of
|
||||
** sqlite_stat2 ANALYZE data, a single inequality reduces the search
|
||||
** space to 1/3rd its original size. So an x>? constraint reduces
|
||||
** nBound to 33. Two constraints (x>? AND x<?) reduce nBound to 11.
|
||||
** estBound to 33. Two constraints (x>? AND x<?) reduce estBound to 11.
|
||||
**
|
||||
** bSort:
|
||||
** Boolean. True if there is an ORDER BY clause that will require an
|
||||
@@ -2345,13 +2604,14 @@ static void bestBtreeIndex(
|
||||
int nEq;
|
||||
int bInEst = 0;
|
||||
int nInMul = 1;
|
||||
int nBound = 100;
|
||||
int estBound = 100;
|
||||
int nBound = 0; /* Number of range constraints seen */
|
||||
int bSort = 0;
|
||||
int bLookup = 0;
|
||||
WhereTerm *pTerm; /* A single term of the WHERE clause */
|
||||
|
||||
/* Determine the values of nEq and nInMul */
|
||||
for(nEq=0; nEq<pProbe->nColumn; nEq++){
|
||||
WhereTerm *pTerm; /* A single term of the WHERE clause */
|
||||
int j = pProbe->aiColumn[nEq];
|
||||
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
|
||||
if( pTerm==0 ) break;
|
||||
@@ -2371,18 +2631,20 @@ static void bestBtreeIndex(
|
||||
used |= pTerm->prereqRight;
|
||||
}
|
||||
|
||||
/* Determine the value of nBound. */
|
||||
/* Determine the value of estBound. */
|
||||
if( nEq<pProbe->nColumn ){
|
||||
int j = pProbe->aiColumn[nEq];
|
||||
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
|
||||
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
|
||||
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
|
||||
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
|
||||
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound);
|
||||
if( pTop ){
|
||||
nBound = 1;
|
||||
wsFlags |= WHERE_TOP_LIMIT;
|
||||
used |= pTop->prereqRight;
|
||||
}
|
||||
if( pBtm ){
|
||||
nBound++;
|
||||
wsFlags |= WHERE_BTM_LIMIT;
|
||||
used |= pBtm->prereqRight;
|
||||
}
|
||||
@@ -2413,7 +2675,7 @@ static void bestBtreeIndex(
|
||||
|
||||
/* If currently calculating the cost of using an index (not the IPK
|
||||
** index), determine if all required column data may be obtained without
|
||||
** seeking to entries in the main table (i.e. if the index is a covering
|
||||
** using the main table (i.e. if the index is a covering
|
||||
** index for this query). If it is, set the WHERE_IDX_ONLY flag in
|
||||
** wsFlags. Otherwise, set the bLookup variable to true. */
|
||||
if( pIdx && wsFlags ){
|
||||
@@ -2432,8 +2694,7 @@ static void bestBtreeIndex(
|
||||
}
|
||||
}
|
||||
|
||||
/**** Begin adding up the cost of using this index (Needs improvements)
|
||||
**
|
||||
/*
|
||||
** Estimate the number of rows of output. For an IN operator,
|
||||
** do not let the estimate exceed half the rows in the table.
|
||||
*/
|
||||
@@ -2452,8 +2713,8 @@ static void bestBtreeIndex(
|
||||
/* Adjust the number of rows and the cost downward to reflect rows
|
||||
** that are excluded by range constraints.
|
||||
*/
|
||||
nRow = (nRow * (double)nBound) / (double)100;
|
||||
cost = (cost * (double)nBound) / (double)100;
|
||||
nRow = (nRow * (double)estBound) / (double)100;
|
||||
cost = (cost * (double)estBound) / (double)100;
|
||||
|
||||
/* Add in the estimated cost of sorting the result
|
||||
*/
|
||||
@@ -2470,17 +2731,75 @@ static void bestBtreeIndex(
|
||||
}
|
||||
/**** Cost of using this index has now been computed ****/
|
||||
|
||||
/* If there are additional constraints on this table that cannot
|
||||
** be used with the current index, but which might lower the number
|
||||
** of output rows, adjust the nRow value accordingly. This only
|
||||
** matters if the current index is the least costly, so do not bother
|
||||
** with this step if we already know this index will not be chosen.
|
||||
** Also, never reduce the output row count below 2 using this step.
|
||||
**
|
||||
** Do not reduce the output row count if pSrc is the only table that
|
||||
** is notReady; if notReady is a power of two. This will be the case
|
||||
** when the main sqlite3WhereBegin() loop is scanning for a table with
|
||||
** and "optimal" index, and on such a scan the output row count
|
||||
** reduction is not valid because it does not update the "pCost->used"
|
||||
** bitmap. The notReady bitmap will also be a power of two when we
|
||||
** are scanning for the last table in a 64-way join. We are willing
|
||||
** to bypass this optimization in that corner case.
|
||||
*/
|
||||
if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){
|
||||
int k; /* Loop counter */
|
||||
int nSkipEq = nEq; /* Number of == constraints to skip */
|
||||
int nSkipRange = nBound; /* Number of < constraints to skip */
|
||||
Bitmask thisTab; /* Bitmap for pSrc */
|
||||
|
||||
thisTab = getMask(pWC->pMaskSet, iCur);
|
||||
for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
|
||||
if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
|
||||
if( (pTerm->prereqAll & notReady)!=thisTab ) continue;
|
||||
if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
|
||||
if( nSkipEq ){
|
||||
/* Ignore the first nEq equality matches since the index
|
||||
** has already accounted for these */
|
||||
nSkipEq--;
|
||||
}else{
|
||||
/* Assume each additional equality match reduces the result
|
||||
** set size by a factor of 10 */
|
||||
nRow /= 10;
|
||||
}
|
||||
}else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){
|
||||
if( nSkipRange ){
|
||||
/* Ignore the first nBound range constraints since the index
|
||||
** has already accounted for these */
|
||||
nSkipRange--;
|
||||
}else{
|
||||
/* Assume each additional range constraint reduces the result
|
||||
** set size by a factor of 3 */
|
||||
nRow /= 3;
|
||||
}
|
||||
}else{
|
||||
/* Any other expression lowers the output row count by half */
|
||||
nRow /= 2;
|
||||
}
|
||||
}
|
||||
if( nRow<2 ) nRow = 2;
|
||||
}
|
||||
|
||||
|
||||
WHERETRACE((
|
||||
"tbl=%s idx=%s nEq=%d nInMul=%d nBound=%d bSort=%d bLookup=%d"
|
||||
" wsFlags=%d (nRow=%.2f cost=%.2f)\n",
|
||||
"%s(%s): nEq=%d nInMul=%d estBound=%d bSort=%d bLookup=%d wsFlags=0x%x\n"
|
||||
" notReady=0x%llx nRow=%.2f cost=%.2f used=0x%llx\n",
|
||||
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
|
||||
nEq, nInMul, nBound, bSort, bLookup, wsFlags, nRow, cost
|
||||
nEq, nInMul, estBound, bSort, bLookup, wsFlags,
|
||||
notReady, nRow, cost, used
|
||||
));
|
||||
|
||||
/* If this index is the best we have seen so far, then record this
|
||||
** index and its cost in the pCost structure.
|
||||
*/
|
||||
if( (!pIdx || wsFlags) && cost<pCost->rCost ){
|
||||
if( (!pIdx || wsFlags)
|
||||
&& (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->nRow))
|
||||
){
|
||||
pCost->rCost = cost;
|
||||
pCost->nRow = nRow;
|
||||
pCost->used = used;
|
||||
@@ -2515,10 +2834,12 @@ static void bestBtreeIndex(
|
||||
);
|
||||
|
||||
WHERETRACE(("best index is: %s\n",
|
||||
(pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
|
||||
((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
|
||||
pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
|
||||
));
|
||||
|
||||
bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
|
||||
bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
|
||||
pCost->plan.wsFlags |= eqTermMask;
|
||||
}
|
||||
|
||||
@@ -2576,7 +2897,7 @@ static void bestIndex(
|
||||
*/
|
||||
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||
if( pTerm
|
||||
&& ALWAYS((pTerm->wtFlags & TERM_CODED)==0)
|
||||
&& (pTerm->wtFlags & TERM_CODED)==0
|
||||
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
||||
){
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
@@ -2774,7 +3095,9 @@ static int codeAllEqualityTerms(
|
||||
int k = pIdx->aiColumn[j];
|
||||
pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx);
|
||||
if( NEVER(pTerm==0) ) break;
|
||||
assert( (pTerm->wtFlags & TERM_CODED)==0 );
|
||||
/* The following true for indices with redundant columns.
|
||||
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
||||
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
|
||||
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
|
||||
if( r1!=regBase+j ){
|
||||
if( nReg==1 ){
|
||||
@@ -2988,7 +3311,11 @@ static Bitmask codeOneLoopStart(
|
||||
pLevel->op = bRev ? OP_Prev : OP_Next;
|
||||
pLevel->p1 = iCur;
|
||||
pLevel->p2 = start;
|
||||
pLevel->p5 = (pStart==0 && pEnd==0) ?1:0;
|
||||
if( pStart==0 && pEnd==0 ){
|
||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||
}else{
|
||||
assert( pLevel->p5==0 );
|
||||
}
|
||||
if( testOp!=OP_Noop ){
|
||||
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
|
||||
@@ -3446,7 +3773,7 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */
|
||||
** Free a WhereInfo structure
|
||||
*/
|
||||
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
if( pWInfo ){
|
||||
if( ALWAYS(pWInfo) ){
|
||||
int i;
|
||||
for(i=0; i<pWInfo->nLevel; i++){
|
||||
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
|
||||
@@ -3457,6 +3784,13 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
}
|
||||
sqlite3DbFree(db, pInfo);
|
||||
}
|
||||
if( pWInfo->a[i].plan.wsFlags & WHERE_TEMP_INDEX ){
|
||||
Index *pIdx = pWInfo->a[i].plan.u.pIdx;
|
||||
if( pIdx ){
|
||||
sqlite3DbFree(db, pIdx->zColAff);
|
||||
sqlite3DbFree(db, pIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
whereClauseClear(pWInfo->pWC);
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
@@ -3576,6 +3910,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
/* The number of tables in the FROM clause is limited by the number of
|
||||
** bits in a Bitmask
|
||||
*/
|
||||
testcase( pTabList->nSrc==BMS );
|
||||
if( pTabList->nSrc>BMS ){
|
||||
sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
|
||||
return 0;
|
||||
@@ -3603,6 +3938,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sizeof(WhereMaskSet)
|
||||
);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
pWInfo = 0;
|
||||
goto whereBeginError;
|
||||
}
|
||||
pWInfo->nLevel = nTabList;
|
||||
@@ -3611,6 +3948,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
|
||||
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
|
||||
pWInfo->wctrlFlags = wctrlFlags;
|
||||
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
|
||||
pMaskSet = (WhereMaskSet*)&pWC[1];
|
||||
|
||||
/* Split the WHERE clause into separate subexpressions where each
|
||||
@@ -3712,20 +4050,25 @@ WhereInfo *sqlite3WhereBegin(
|
||||
bestPlan.rCost = SQLITE_BIG_DBL;
|
||||
|
||||
/* Loop through the remaining entries in the FROM clause to find the
|
||||
** next nested loop. The FROM clause entries may be iterated through
|
||||
** next nested loop. The loop tests all FROM clause entries
|
||||
** either once or twice.
|
||||
**
|
||||
** The first iteration, which is always performed, searches for the
|
||||
** FROM clause entry that permits the lowest-cost, "optimal" scan. In
|
||||
** The first test is always performed if there are two or more entries
|
||||
** remaining and never performed if there is only one FROM clause entry
|
||||
** to choose from. The first test looks for an "optimal" scan. In
|
||||
** this context an optimal scan is one that uses the same strategy
|
||||
** for the given FROM clause entry as would be selected if the entry
|
||||
** were used as the innermost nested loop. In other words, a table
|
||||
** is chosen such that the cost of running that table cannot be reduced
|
||||
** by waiting for other tables to run first.
|
||||
** by waiting for other tables to run first. This "optimal" test works
|
||||
** by first assuming that the FROM clause is on the inner loop and finding
|
||||
** its query plan, then checking to see if that query plan uses any
|
||||
** other FROM clause terms that are notReady. If no notReady terms are
|
||||
** used then the "optimal" query plan works.
|
||||
**
|
||||
** The second iteration is only performed if no optimal scan strategies
|
||||
** were found by the first. This iteration is used to search for the
|
||||
** lowest cost scan overall.
|
||||
** The second loop iteration is only performed if no optimal scan
|
||||
** strategies were found by the first loop. This 2nd iteration is used to
|
||||
** search for the lowest cost scan overall.
|
||||
**
|
||||
** Previous versions of SQLite performed only the second iteration -
|
||||
** the next outermost loop was always that with the lowest overall
|
||||
@@ -3743,9 +4086,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** algorithm may choose to use t2 for the outer loop, which is a much
|
||||
** costlier approach.
|
||||
*/
|
||||
for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
|
||||
Bitmask mask = (isOptimal ? 0 : notReady);
|
||||
assert( (nTabList-iFrom)>1 || isOptimal );
|
||||
for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
|
||||
Bitmask mask; /* Mask of tables not yet ready */
|
||||
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
|
||||
int doNotReorder; /* True if this table should not be reordered */
|
||||
WhereCost sCost; /* Cost information from best[Virtual]Index() */
|
||||
@@ -3758,6 +4100,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( j==iFrom ) iFrom++;
|
||||
continue;
|
||||
}
|
||||
mask = (isOptimal ? m : notReady);
|
||||
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
|
||||
|
||||
assert( pTabItem->pTab );
|
||||
@@ -3773,8 +4116,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
assert( isOptimal || (sCost.used¬Ready)==0 );
|
||||
|
||||
if( (sCost.used¬Ready)==0
|
||||
&& (j==iFrom || sCost.rCost<bestPlan.rCost)
|
||||
&& (bestJ<0 || sCost.rCost<bestPlan.rCost
|
||||
|| (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
|
||||
){
|
||||
WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
|
||||
sCost.rCost, sCost.nRow));
|
||||
bestPlan = sCost;
|
||||
bestJ = j;
|
||||
}
|
||||
@@ -3790,13 +4136,16 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
andFlags &= bestPlan.plan.wsFlags;
|
||||
pLevel->plan = bestPlan.plan;
|
||||
if( bestPlan.plan.wsFlags & WHERE_INDEXED ){
|
||||
testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
|
||||
testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
|
||||
if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
|
||||
pLevel->iIdxCur = pParse->nTab++;
|
||||
}else{
|
||||
pLevel->iIdxCur = -1;
|
||||
}
|
||||
notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
|
||||
pLevel->iFrom = (u8)bestJ;
|
||||
if( bestPlan.nRow>=(double)1 ) pParse->nQueryLoop *= bestPlan.nRow;
|
||||
|
||||
/* Check that if the table scanned by this loop iteration had an
|
||||
** INDEXED BY clause attached to it, that the named index is being
|
||||
@@ -3843,6 +4192,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** searching those tables.
|
||||
*/
|
||||
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
|
||||
notReady = ~(Bitmask)0;
|
||||
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
|
||||
Table *pTab; /* Table to open */
|
||||
int iDb; /* Index of database containing table/index */
|
||||
@@ -3855,7 +4205,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( pItem->zAlias ){
|
||||
zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
|
||||
}
|
||||
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
||||
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
|
||||
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH AUTOMATIC INDEX", zMsg);
|
||||
}else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
||||
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s",
|
||||
zMsg, pLevel->plan.u.pIdx->zName);
|
||||
}else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
|
||||
@@ -3878,8 +4230,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
pTab = pTabItem->pTab;
|
||||
pLevel->iTabCur = pTabItem->iCursor;
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
|
||||
/* Do nothing */
|
||||
}else
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
||||
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
||||
@@ -3891,6 +4246,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
&& (wctrlFlags & WHERE_OMIT_OPEN)==0 ){
|
||||
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
|
||||
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
|
||||
testcase( pTab->nCol==BMS-1 );
|
||||
testcase( pTab->nCol==BMS );
|
||||
if( !pWInfo->okOnePass && pTab->nCol<BMS ){
|
||||
Bitmask b = pTabItem->colUsed;
|
||||
int n = 0;
|
||||
@@ -3902,7 +4259,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}else{
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
}
|
||||
pLevel->iTabCur = pTabItem->iCursor;
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
|
||||
constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
|
||||
}else
|
||||
#endif
|
||||
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
||||
Index *pIx = pLevel->plan.u.pIdx;
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
|
||||
@@ -3914,8 +4275,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
VdbeComment((v, "%s", pIx->zName));
|
||||
}
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
|
||||
}
|
||||
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
|
||||
if( db->mallocFailed ) goto whereBeginError;
|
||||
|
||||
/* Generate the code to do the search. Each iteration of the for
|
||||
** loop below generates code for a single nested loop of the VM
|
||||
@@ -3983,7 +4346,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
|
||||
/* Jump here if malloc fails */
|
||||
whereBeginError:
|
||||
whereInfoFree(db, pWInfo);
|
||||
if( pWInfo ){
|
||||
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
||||
whereInfoFree(db, pWInfo);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4053,12 +4419,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
Table *pTab = pTabItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
||||
if( (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 ){
|
||||
if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
|
||||
if( (pTab->tabFlags & TF_Ephemeral)==0
|
||||
&& pTab->pSelect==0
|
||||
&& (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0
|
||||
){
|
||||
int ws = pLevel->plan.wsFlags;
|
||||
if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
|
||||
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
||||
}
|
||||
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
||||
if( (ws & WHERE_INDEXED)!=0 && (ws & WHERE_TEMP_INDEX)==0 ){
|
||||
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
||||
}
|
||||
}
|
||||
@@ -4106,6 +4475,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
|
||||
/* Final cleanup
|
||||
*/
|
||||
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
||||
whereInfoFree(db, pWInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
+23
-8
@@ -173,6 +173,20 @@ ifcapable tempdb {
|
||||
}
|
||||
}
|
||||
|
||||
# Create bogus application-defined functions for functions used
|
||||
# internally by ALTER TABLE, to ensure that ALTER TABLE falls back
|
||||
# to the built-in functions.
|
||||
#
|
||||
proc failing_app_func {args} {error "bad function"}
|
||||
do_test alter-1.7-prep {
|
||||
db func substr failing_app_func
|
||||
db func like failing_app_func
|
||||
db func sqlite_rename_table failing_app_func
|
||||
db func sqlite_rename_trigger failing_app_func
|
||||
db func sqlite_rename_parent failing_app_func
|
||||
catchsql {SELECT substr(name,1,3) FROM sqlite_master}
|
||||
} {1 {bad function}}
|
||||
|
||||
# Make sure the ALTER TABLE statements work with the
|
||||
# non-callback API
|
||||
#
|
||||
@@ -567,7 +581,8 @@ do_test alter-5.3 {
|
||||
} {}
|
||||
|
||||
foreach tblname [execsql {
|
||||
SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite%'
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='table' AND name NOT GLOB 'sqlite*'
|
||||
}] {
|
||||
execsql "DROP TABLE \"$tblname\""
|
||||
}
|
||||
@@ -688,17 +703,17 @@ do_test alter-9.2 {
|
||||
do_test alter-10.1 {
|
||||
execsql "CREATE TABLE xyz(x UNIQUE)"
|
||||
execsql "ALTER TABLE xyz RENAME TO xyz\u1234abc"
|
||||
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'xyz%'}
|
||||
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'xyz*'}
|
||||
} [list xyz\u1234abc]
|
||||
do_test alter-10.2 {
|
||||
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
|
||||
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_autoindex*'}
|
||||
} [list sqlite_autoindex_xyz\u1234abc_1]
|
||||
do_test alter-10.3 {
|
||||
execsql "ALTER TABLE xyz\u1234abc RENAME TO xyzabc"
|
||||
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'xyz%'}
|
||||
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'xyz*'}
|
||||
} [list xyzabc]
|
||||
do_test alter-10.4 {
|
||||
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
|
||||
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_autoindex*'}
|
||||
} [list sqlite_autoindex_xyzabc_1]
|
||||
|
||||
do_test alter-11.1 {
|
||||
@@ -795,19 +810,19 @@ do_test alter-13.1 {
|
||||
CREATE TABLE t3102b -- comment
|
||||
(y);
|
||||
CREATE INDEX t3102c ON t3102a(x);
|
||||
SELECT name FROM sqlite_master WHERE name LIKE 't3102%' ORDER BY 1;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB 't3102*' ORDER BY 1;
|
||||
}
|
||||
} {t3102a t3102b t3102c}
|
||||
do_test alter-13.2 {
|
||||
execsql {
|
||||
ALTER TABLE t3102a RENAME TO t3102a_rename;
|
||||
SELECT name FROM sqlite_master WHERE name LIKE 't3102%' ORDER BY 1;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB 't3102*' ORDER BY 1;
|
||||
}
|
||||
} {t3102a_rename t3102b t3102c}
|
||||
do_test alter-13.3 {
|
||||
execsql {
|
||||
ALTER TABLE t3102b RENAME TO t3102b_rename;
|
||||
SELECT name FROM sqlite_master WHERE name LIKE 't3102%' ORDER BY 1;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB 't3102*' ORDER BY 1;
|
||||
}
|
||||
} {t3102a_rename t3102b_rename t3102c}
|
||||
|
||||
|
||||
@@ -72,6 +72,21 @@ proc alter_table {tbl sql {file_format 2}} {
|
||||
set_file_format 2
|
||||
}
|
||||
|
||||
# Create bogus application-defined functions for functions used
|
||||
# internally by ALTER TABLE, to ensure that ALTER TABLE falls back
|
||||
# to the built-in functions.
|
||||
#
|
||||
proc failing_app_func {args} {error "bad function"}
|
||||
do_test alter2-1.0 {
|
||||
db func substr failing_app_func
|
||||
db func like failing_app_func
|
||||
db func sqlite_rename_table failing_app_func
|
||||
db func sqlite_rename_trigger failing_app_func
|
||||
db func sqlite_rename_parent failing_app_func
|
||||
catchsql {SELECT substr('abcdefg',1,3)}
|
||||
} {1 {bad function}}
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Some basic tests to make sure short rows are handled.
|
||||
#
|
||||
|
||||
@@ -94,6 +94,7 @@ do_test async4.1.14 {
|
||||
do_test async4.1.15 {
|
||||
sqlite3async_start
|
||||
sqlite3async_wait
|
||||
hexio_write test.db 28 00000000
|
||||
execsql { pragma integrity_check } db2
|
||||
} {{*** in database main ***
|
||||
Page 5 is never used}}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
# 2010 April 07
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing automatic index creation logic.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# If the library is not compiled with automatic index support then
|
||||
# skip all tests in this file.
|
||||
#
|
||||
ifcapable {!autoindex} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# With automatic index turned off, we do a full scan of the T2 table
|
||||
do_test autoindex1-100 {
|
||||
db eval {
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1 VALUES(1,11);
|
||||
INSERT INTO t1 VALUES(2,22);
|
||||
INSERT INTO t1 SELECT a+2, b+22 FROM t1;
|
||||
INSERT INTO t1 SELECT a+4, b+44 FROM t1;
|
||||
CREATE TABLE t2(c,d);
|
||||
INSERT INTO t2 SELECT a, 900+b FROM t1;
|
||||
}
|
||||
db eval {
|
||||
PRAGMA automatic_index=OFF;
|
||||
SELECT b, d FROM t1 JOIN t2 ON a=c ORDER BY b;
|
||||
}
|
||||
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
|
||||
do_test autoindex1-101 {
|
||||
db status step
|
||||
} {63}
|
||||
do_test autoindex1-102 {
|
||||
db status autoindex
|
||||
} {0}
|
||||
|
||||
# With autoindex turned on, we build an index once and then use that index
|
||||
# to find T2 values.
|
||||
do_test autoindex1-110 {
|
||||
db eval {
|
||||
PRAGMA automatic_index=ON;
|
||||
SELECT b, d FROM t1 JOIN t2 ON a=c ORDER BY b;
|
||||
}
|
||||
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
|
||||
do_test autoindex1-111 {
|
||||
db status step
|
||||
} {7}
|
||||
do_test autoindex1-112 {
|
||||
db status autoindex
|
||||
} {7}
|
||||
|
||||
# The same test as above, but this time the T2 query is a subquery rather
|
||||
# than a join.
|
||||
do_test autoindex1-200 {
|
||||
db eval {
|
||||
PRAGMA automatic_index=OFF;
|
||||
SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
|
||||
}
|
||||
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
|
||||
do_test autoindex1-201 {
|
||||
db status step
|
||||
} {35}
|
||||
do_test autoindex1-202 {
|
||||
db status autoindex
|
||||
} {0}
|
||||
do_test autoindex1-210 {
|
||||
db eval {
|
||||
PRAGMA automatic_index=ON;
|
||||
SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
|
||||
}
|
||||
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
|
||||
do_test autoindex1-211 {
|
||||
db status step
|
||||
} {7}
|
||||
do_test autoindex1-212 {
|
||||
db status autoindex
|
||||
} {7}
|
||||
|
||||
|
||||
# Modify the second table of the join while the join is in progress
|
||||
#
|
||||
do_test autoindex1-300 {
|
||||
set r {}
|
||||
db eval {SELECT b, d FROM t1 JOIN t2 ON (c=a)} {
|
||||
lappend r $b $d
|
||||
db eval {UPDATE t2 SET d=d+1}
|
||||
}
|
||||
set r
|
||||
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
|
||||
do_test autoindex1-310 {
|
||||
db eval {SELECT d FROM t2 ORDER BY d}
|
||||
} {919 930 941 952 963 974 985 996}
|
||||
|
||||
# The next test does a 10-way join on unindexed tables. Without
|
||||
# automatic indices, the join will take a long time to complete.
|
||||
# With automatic indices, it should only take about a second.
|
||||
#
|
||||
do_test autoindex1-400 {
|
||||
db eval {
|
||||
CREATE TABLE t4(a, b);
|
||||
INSERT INTO t4 VALUES(1,2);
|
||||
INSERT INTO t4 VALUES(2,3);
|
||||
}
|
||||
for {set n 2} {$n<4096} {set n [expr {$n+$n}]} {
|
||||
db eval {INSERT INTO t4 SELECT a+$n, b+$n FROM t4}
|
||||
}
|
||||
db eval {
|
||||
SELECT count(*) FROM t4;
|
||||
}
|
||||
} {4096}
|
||||
do_test autoindex1-401 {
|
||||
db eval {
|
||||
SELECT count(*)
|
||||
FROM t4 AS x1
|
||||
JOIN t4 AS x2 ON x2.a=x1.b
|
||||
JOIN t4 AS x3 ON x3.a=x2.b
|
||||
JOIN t4 AS x4 ON x4.a=x3.b
|
||||
JOIN t4 AS x5 ON x5.a=x4.b
|
||||
JOIN t4 AS x6 ON x6.a=x5.b
|
||||
JOIN t4 AS x7 ON x7.a=x6.b
|
||||
JOIN t4 AS x8 ON x8.a=x7.b
|
||||
JOIN t4 AS x9 ON x9.a=x8.b
|
||||
JOIN t4 AS x10 ON x10.a=x9.b;
|
||||
}
|
||||
} {4087}
|
||||
|
||||
finish_test
|
||||
+7
-2
@@ -22,8 +22,9 @@ source $testdir/tester.tcl
|
||||
# Create several tables to work with.
|
||||
#
|
||||
do_test avtrans-1.0 {
|
||||
execsql {
|
||||
PRAGMA auto_vacuum=ON;
|
||||
execsql { PRAGMA auto_vacuum=ON }
|
||||
wal_set_journal_mode
|
||||
execsql {
|
||||
CREATE TABLE one(a int PRIMARY KEY, b text);
|
||||
INSERT INTO one VALUES(1,'one');
|
||||
INSERT INTO one VALUES(2,'two');
|
||||
@@ -48,6 +49,7 @@ do_test avtrans-1.10 {
|
||||
execsql {SELECT b FROM two ORDER BY a} altdb
|
||||
} {I V X}
|
||||
integrity_check avtrans-1.11
|
||||
wal_check_journal_mode avtrans-1.12
|
||||
|
||||
# Basic transactions
|
||||
#
|
||||
@@ -84,6 +86,7 @@ do_test avtrans-2.10 {
|
||||
}
|
||||
} {1 2 3 1 5 10}
|
||||
integrity_check avtrans-2.11
|
||||
wal_check_journal_mode avtrans-2.12
|
||||
|
||||
# Check the locking behavior
|
||||
#
|
||||
@@ -913,9 +916,11 @@ for {set i 2} {$i<=$limit} {incr i} {
|
||||
} {1}
|
||||
}
|
||||
}
|
||||
wal_check_journal_mode avtrans-9.$i-6.$cnt
|
||||
}
|
||||
set ::pager_old_format 0
|
||||
}
|
||||
integrity_check avtrans-10.1
|
||||
wal_check_journal_mode avtrans-10.2
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -38,6 +38,8 @@ source $testdir/tester.tcl
|
||||
#
|
||||
# backup-9.*: Test that passing a negative argument to backup_step() is
|
||||
# interpreted as "copy the whole file".
|
||||
#
|
||||
# backup-10.*: Test writing the source database mid backup.
|
||||
#
|
||||
|
||||
proc data_checksum {db file} { $db one "SELECT md5sum(a, b) FROM ${file}.t1" }
|
||||
@@ -487,6 +489,7 @@ db2 close
|
||||
# 3) Backing up memory-to-file.
|
||||
#
|
||||
set iTest 0
|
||||
file delete -force bak.db-wal
|
||||
foreach {writer file} {db test.db db3 test.db db :memory:} {
|
||||
incr iTest
|
||||
catch { file delete bak.db }
|
||||
@@ -905,6 +908,7 @@ ifcapable memorymanage {
|
||||
}
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Test that if the database is written to via the same database handle being
|
||||
# used as the source by a backup operation:
|
||||
#
|
||||
|
||||
@@ -69,6 +69,7 @@ if {[catch {fake_big_file 4096 [pwd]/test.db} msg]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
hexio_write test.db 28 00000000
|
||||
|
||||
do_test bigfile-1.2 {
|
||||
sqlite3 db test.db
|
||||
@@ -108,6 +109,7 @@ if {[catch {fake_big_file 8192 [pwd]/test.db}]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
hexio_write test.db 28 00000000
|
||||
|
||||
do_test bigfile-1.5 {
|
||||
sqlite3 db test.db
|
||||
@@ -146,6 +148,7 @@ if {[catch {fake_big_file 16384 [pwd]/test.db}]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
hexio_write test.db 28 00000000
|
||||
|
||||
do_test bigfile-1.10 {
|
||||
sqlite3 db test.db
|
||||
|
||||
+6
-2
@@ -71,15 +71,19 @@ do_test capi2-1.6 {
|
||||
do_test capi2-1.7 {
|
||||
list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM]
|
||||
} {2 {} {name rowid text INTEGER}}
|
||||
do_test capi2-1.8-misuse {
|
||||
|
||||
# This used to be SQLITE_MISUSE. But now we automatically reset prepared
|
||||
# statements.
|
||||
do_test capi2-1.8 {
|
||||
sqlite3_step $VM
|
||||
} {SQLITE_MISUSE}
|
||||
} {SQLITE_ROW}
|
||||
|
||||
# Update: In v2, once SQLITE_MISUSE is returned the statement handle cannot
|
||||
# be interrogated for more information. However in v3, since the column
|
||||
# count, names and types are determined at compile time, these are still
|
||||
# accessible after an SQLITE_MISUSE error.
|
||||
do_test capi2-1.9 {
|
||||
sqlite3_reset $VM
|
||||
list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM]
|
||||
} {2 {} {name rowid text INTEGER}}
|
||||
do_test capi2-1.10 {
|
||||
|
||||
+2
-1
@@ -321,6 +321,7 @@ do_test collate4-1.2.25 {
|
||||
#
|
||||
do_test collate4-2.1.0 {
|
||||
execsql {
|
||||
PRAGMA automatic_index=OFF;
|
||||
CREATE TABLE collate4t1(a COLLATE NOCASE);
|
||||
CREATE TABLE collate4t2(b COLLATE TEXT);
|
||||
|
||||
@@ -426,7 +427,7 @@ do_test collate4-2.2.0 {
|
||||
} {}
|
||||
do_test collate4-2.2.1 {
|
||||
count {
|
||||
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
|
||||
SELECT * FROM collate4t2 NOT INDEXED NATURAL JOIN collate4t1 NOT INDEXED;
|
||||
}
|
||||
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 63}
|
||||
do_test collate4-2.2.1b {
|
||||
|
||||
@@ -334,6 +334,7 @@ ifcapable autovacuum {
|
||||
seek $fd 0 end
|
||||
puts -nonewline $fd [string repeat x $nAppend]
|
||||
close $fd
|
||||
hexio_write corrupt.db 28 00000000
|
||||
} -test {
|
||||
do_test corrupt2-6.4 {
|
||||
catchsql {
|
||||
@@ -522,6 +523,7 @@ ifcapable autovacuum {
|
||||
file size corrupt.db
|
||||
} $::sqlite_pending_byte
|
||||
hexio_write corrupt.db [expr $::sqlite_pending_byte+1023] 00
|
||||
hexio_write corrupt.db 28 00000000
|
||||
} -test {
|
||||
do_test corrupt2-13.2 {
|
||||
file size corrupt.db
|
||||
|
||||
+3
-1
@@ -37,9 +37,11 @@ integrity_check corruptA-1.2
|
||||
db close
|
||||
file copy -force test.db test.db-template
|
||||
|
||||
set unreadable_version 02
|
||||
ifcapable wal { set unreadable_version 03 }
|
||||
do_test corruptA-2.1 {
|
||||
file copy -force test.db-template test.db
|
||||
hexio_write test.db 19 02 ;# the read format number
|
||||
hexio_write test.db 19 $unreadable_version ;# the read format number
|
||||
sqlite3 db test.db
|
||||
catchsql {SELECT * FROM t1}
|
||||
} {1 {file is encrypted or is not a database}}
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ do_test corruptB-2.1.1 {
|
||||
do_test corruptB-2.1.2 {
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {1 {database or disk is full}}
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -21,6 +21,13 @@ catch {file delete -force test.db test.db-journal test.bu}
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Do not run the tests in this file if ENABLE_OVERSIZE_CELL_CHECK is on.
|
||||
#
|
||||
ifcapable oversize_cell_check {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Construct a compact, dense database for testing.
|
||||
#
|
||||
do_test corruptE-1.1 {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# 2010 March 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests for the sqlite3_db_status() function
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
|
||||
# Make sure sqlite3_db_config() and sqlite3_db_status are working.
|
||||
#
|
||||
unset -nocomplain PAGESZ
|
||||
unset -nocomplain BASESZ
|
||||
do_test dbstatus-1.1 {
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
db eval {
|
||||
CREATE TABLE t1(x);
|
||||
}
|
||||
set sz1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
|
||||
db eval {
|
||||
CREATE TABLE t2(y);
|
||||
}
|
||||
set sz2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
|
||||
set ::PAGESZ [expr {$sz2-$sz1}]
|
||||
set ::BASESZ [expr {$sz1-$::PAGESZ}]
|
||||
expr {$::PAGESZ>1024 && $::PAGESZ<1200}
|
||||
} {1}
|
||||
do_test dbstatus-1.2 {
|
||||
db eval {
|
||||
INSERT INTO t1 VALUES(zeroblob(9000));
|
||||
}
|
||||
lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1
|
||||
} [expr {$BASESZ + 10*$PAGESZ}]
|
||||
|
||||
finish_test
|
||||
@@ -252,6 +252,7 @@ ddl_test 1.3.2.8 { DROP TABLE docs }
|
||||
# Test the examples in section 3 (full-text index queries).
|
||||
#
|
||||
ddl_test 1.4.1.1 { CREATE VIRTUAL TABLE docs USING fts3(title, body) }
|
||||
unset -nocomplain R
|
||||
foreach {tn title body} {
|
||||
2 "linux driver" "a device"
|
||||
3 "driver" "linguistic trick"
|
||||
|
||||
+27
-1
@@ -1410,7 +1410,7 @@ do_test fkey2-17.1.2 {
|
||||
} {SQLITE_CONSTRAINT}
|
||||
do_test fkey2-17.1.3 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_MISUSE}
|
||||
} {SQLITE_CONSTRAINT}
|
||||
do_test fkey2-17.1.4 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_CONSTRAINT}
|
||||
@@ -1598,6 +1598,32 @@ ifcapable auth {
|
||||
unset authargs
|
||||
}
|
||||
|
||||
|
||||
do_test fkey2-19.1 {
|
||||
execsql {
|
||||
CREATE TABLE main(id INTEGER PRIMARY KEY);
|
||||
CREATE TABLE sub(id INT REFERENCES main(id));
|
||||
INSERT INTO main VALUES(1);
|
||||
INSERT INTO main VALUES(2);
|
||||
INSERT INTO sub VALUES(2);
|
||||
}
|
||||
} {}
|
||||
do_test fkey2-19.2 {
|
||||
set S [sqlite3_prepare_v2 db "DELETE FROM main WHERE id = ?" -1 dummy]
|
||||
sqlite3_bind_int $S 1 2
|
||||
sqlite3_step $S
|
||||
} {SQLITE_CONSTRAINT}
|
||||
do_test fkey2-19.3 {
|
||||
sqlite3_reset $S
|
||||
} {SQLITE_CONSTRAINT}
|
||||
do_test fkey2-19.4 {
|
||||
sqlite3_bind_int $S 1 1
|
||||
sqlite3_step $S
|
||||
} {SQLITE_DONE}
|
||||
do_test fkey2-19.4 {
|
||||
sqlite3_finalize $S
|
||||
} {SQLITE_OK}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following block of tests, those prefixed with "fkey2-genfkey.", are
|
||||
# the same tests that were used to test the ".genfkey" command provided
|
||||
|
||||
@@ -288,155 +288,3 @@ proc fts3_read {tbl where varname} {
|
||||
|
||||
##########################################################################
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This proc is used to test a single SELECT statement. Parameter $name is
|
||||
# passed a name for the test case (i.e. "fts3_malloc-1.4.1") and parameter
|
||||
# $sql is passed the text of the SELECT statement. Parameter $result is
|
||||
# set to the expected output if the SELECT statement is successfully
|
||||
# executed using [db eval].
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# do_select_test testcase-1.1 "SELECT 1+1, 1+2" {1 2}
|
||||
#
|
||||
# If global variable DO_MALLOC_TEST is set to a non-zero value, or if
|
||||
# it is not defined at all, then OOM testing is performed on the SELECT
|
||||
# statement. Each OOM test case is said to pass if either (a) executing
|
||||
# the SELECT statement succeeds and the results match those specified
|
||||
# by parameter $result, or (b) TCL throws an "out of memory" error.
|
||||
#
|
||||
# If DO_MALLOC_TEST is defined and set to zero, then the SELECT statement
|
||||
# is executed just once. In this case the test case passes if the results
|
||||
# match the expected results passed via parameter $result.
|
||||
#
|
||||
proc do_select_test {name sql result} {
|
||||
uplevel [list doPassiveTest 0 $name $sql [list 0 $result]]
|
||||
}
|
||||
|
||||
proc do_restart_select_test {name sql result} {
|
||||
uplevel [list doPassiveTest 1 $name $sql [list 0 $result]]
|
||||
}
|
||||
|
||||
proc do_error_test {name sql error} {
|
||||
uplevel [list doPassiveTest 0 $name $sql [list 1 $error]]
|
||||
}
|
||||
|
||||
proc doPassiveTest {isRestart name sql catchres} {
|
||||
if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
|
||||
|
||||
switch $::DO_MALLOC_TEST {
|
||||
0 { # No malloc failures.
|
||||
do_test $name [list set {} [uplevel [list catchsql $sql]]] $catchres
|
||||
return
|
||||
}
|
||||
1 { # Simulate transient failures.
|
||||
set nRepeat 1
|
||||
set zName "transient"
|
||||
set nStartLimit 100000
|
||||
set nBackup 1
|
||||
}
|
||||
2 { # Simulate persistent failures.
|
||||
set nRepeat 1
|
||||
set zName "persistent"
|
||||
set nStartLimit 100000
|
||||
set nBackup 1
|
||||
}
|
||||
3 { # Simulate transient failures with extra brute force.
|
||||
set nRepeat 100000
|
||||
set zName "ridiculous"
|
||||
set nStartLimit 1
|
||||
set nBackup 10
|
||||
}
|
||||
}
|
||||
|
||||
# The set of acceptable results from running [catchsql $sql].
|
||||
#
|
||||
set answers [list {1 {out of memory}} $catchres]
|
||||
set str [join $answers " OR "]
|
||||
|
||||
set nFail 1
|
||||
for {set iLimit $nStartLimit} {$nFail} {incr iLimit} {
|
||||
for {set iFail 1} {$nFail && $iFail<=$iLimit} {incr iFail} {
|
||||
for {set iTest 0} {$iTest<$nBackup && ($iFail-$iTest)>0} {incr iTest} {
|
||||
|
||||
if {$isRestart} { sqlite3 db test.db }
|
||||
|
||||
sqlite3_memdebug_fail [expr $iFail-$iTest] -repeat $nRepeat
|
||||
set res [uplevel [list catchsql $sql]]
|
||||
if {[lsearch -exact $answers $res]>=0} { set res $str }
|
||||
set testname "$name.$zName.$iFail"
|
||||
do_test "$name.$zName.$iLimit.$iFail" [list set {} $res] $str
|
||||
|
||||
set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test a single write to the database. In this case a "write" is a
|
||||
# DELETE, UPDATE or INSERT statement.
|
||||
#
|
||||
# If OOM testing is performed, there are several acceptable outcomes:
|
||||
#
|
||||
# 1) The write succeeds. No error is returned.
|
||||
#
|
||||
# 2) An "out of memory" exception is thrown and:
|
||||
#
|
||||
# a) The statement has no effect, OR
|
||||
# b) The current transaction is rolled back, OR
|
||||
# c) The statement succeeds. This can only happen if the connection
|
||||
# is in auto-commit mode (after the statement is executed, so this
|
||||
# includes COMMIT statements).
|
||||
#
|
||||
# If the write operation eventually succeeds, zero is returned. If a
|
||||
# transaction is rolled back, non-zero is returned.
|
||||
#
|
||||
# Parameter $name is the name to use for the test case (or test cases).
|
||||
# The second parameter, $tbl, should be the name of the database table
|
||||
# being modified. Parameter $sql contains the SQL statement to test.
|
||||
#
|
||||
proc do_write_test {name tbl sql} {
|
||||
if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
|
||||
|
||||
# Figure out an statement to get a checksum for table $tbl.
|
||||
db eval "SELECT * FROM $tbl" V break
|
||||
set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl"
|
||||
|
||||
# Calculate the initial table checksum.
|
||||
set cksum1 [db one $cksumsql]
|
||||
|
||||
if {$::DO_MALLOC_TEST } {
|
||||
set answers [list {1 {out of memory}} {0 {}}]
|
||||
if {$::DO_MALLOC_TEST==1} {
|
||||
set modes {100000 transient}
|
||||
} else {
|
||||
set modes {1 persistent}
|
||||
}
|
||||
} else {
|
||||
set answers [list {0 {}}]
|
||||
set modes [list 0 nofail]
|
||||
}
|
||||
set str [join $answers " OR "]
|
||||
|
||||
foreach {nRepeat zName} $modes {
|
||||
for {set iFail 1} 1 {incr iFail} {
|
||||
if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat}
|
||||
|
||||
set res [uplevel [list catchsql $sql]]
|
||||
set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
|
||||
if {$nFail==0} {
|
||||
do_test $name.$zName.$iFail [list set {} $res] {0 {}}
|
||||
return
|
||||
} else {
|
||||
if {[lsearch $answers $res]>=0} {
|
||||
set res $str
|
||||
}
|
||||
do_test $name.$zName.$iFail [list set {} $res] $str
|
||||
set cksum2 [db one $cksumsql]
|
||||
if {$cksum1 != $cksum2} return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ source $testdir/tester.tcl
|
||||
# If this build does not include FTS3, skip the tests in this file.
|
||||
#
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
source $testdir/malloc_common.tcl
|
||||
source $testdir/fts3_common.tcl
|
||||
set DO_MALLOC_TEST 0
|
||||
|
||||
@@ -101,5 +102,33 @@ do_test fts3query-3.3 {
|
||||
execsql { SELECT mit(matchinfo(foobar)) FROM foobar WHERE foobar MATCH 'the' }
|
||||
} {{1 1 3 3 1}}
|
||||
|
||||
# The following tests check that ticket 775b39dd3c has been fixed.
|
||||
#
|
||||
proc eqp {sql} {
|
||||
uplevel [list execsql "EXPLAIN QUERY PLAN $sql"]
|
||||
}
|
||||
do_test fts3query-4.1 {
|
||||
execsql {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(number INTEGER PRIMARY KEY, date);
|
||||
CREATE INDEX i1 ON t1(date);
|
||||
CREATE VIRTUAL TABLE ft USING fts3(title);
|
||||
CREATE TABLE bt(title);
|
||||
}
|
||||
} {}
|
||||
do_test fts3query-4.2 {
|
||||
eqp "SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date"
|
||||
} {0 0 {TABLE t1 WITH INDEX i1 ORDER BY} 1 1 {TABLE ft VIRTUAL TABLE INDEX 1:}}
|
||||
do_test fts3query-4.3 {
|
||||
eqp "SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date"
|
||||
} {0 1 {TABLE t1 WITH INDEX i1 ORDER BY} 1 0 {TABLE ft VIRTUAL TABLE INDEX 1:}}
|
||||
do_test fts3query-4.4 {
|
||||
eqp "SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date"
|
||||
} {0 0 {TABLE t1 WITH INDEX i1 ORDER BY} 1 1 {TABLE bt USING PRIMARY KEY}}
|
||||
do_test fts3query-4.5 {
|
||||
eqp "SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date"
|
||||
} {0 1 {TABLE t1 WITH INDEX i1 ORDER BY} 1 0 {TABLE bt USING PRIMARY KEY}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ source $testdir/tester.tcl
|
||||
#
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
source $testdir/fts3_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
set G(nVocab) 100
|
||||
|
||||
|
||||
@@ -334,4 +334,31 @@ do_test hook-5.2.2 {
|
||||
# End rollback-hook testing.
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test that if a commit-hook returns non-zero (causing a rollback), the
|
||||
# rollback-hook is invoked.
|
||||
#
|
||||
proc commit_hook {} {
|
||||
lappend ::hooks COMMIT
|
||||
return 1
|
||||
}
|
||||
proc rollback_hook {} {
|
||||
lappend ::hooks ROLLBACK
|
||||
}
|
||||
do_test hook-6.1 {
|
||||
set ::hooks [list]
|
||||
db commit_hook commit_hook
|
||||
db rollback_hook rollback_hook
|
||||
catchsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('two', 'II');
|
||||
COMMIT;
|
||||
}
|
||||
execsql { SELECT * FROM t1 }
|
||||
} {one I}
|
||||
do_test hook-6.2 {
|
||||
set ::hooks
|
||||
} {COMMIT ROLLBACK}
|
||||
unset ::hooks
|
||||
|
||||
finish_test
|
||||
|
||||
+4
-1
@@ -17,6 +17,10 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
if {[db eval {SELECT sqlite_compileoption_used('THREADSAFE=0')}]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
db close
|
||||
|
||||
@@ -76,4 +80,3 @@ if {$MEMDEBUG} {
|
||||
|
||||
autoinstall_test_functions
|
||||
finish_test
|
||||
|
||||
|
||||
+13
-4
@@ -200,10 +200,16 @@ do_test io-2.5.3 {
|
||||
# journal file is not actually created until the 'COMMIT' statement
|
||||
# is executed.
|
||||
#
|
||||
# Changed 2010-03-27: The size of the database is now stored in
|
||||
# bytes 28..31 and so when a page is added to the database, page 1
|
||||
# is immediately modified and the journal file immediately comes into
|
||||
# existance. To fix this test, the BEGIN is changed into a a
|
||||
# BEGIN IMMEDIATE and the INSERT is omitted.
|
||||
#
|
||||
do_test io-2.6.1 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO abc VALUES(9, randstr(1000,1000));
|
||||
BEGIN IMMEDIATE;
|
||||
-- INSERT INTO abc VALUES(9, randstr(1000,1000));
|
||||
}
|
||||
file exists test.db-journal
|
||||
} {0}
|
||||
@@ -213,12 +219,15 @@ do_test io-2.6.2 {
|
||||
# should fail with SQLITE_CANTOPEN and the transaction rolled back.
|
||||
#
|
||||
file mkdir test.db-journal
|
||||
catchsql { COMMIT }
|
||||
catchsql {
|
||||
INSERT INTO abc VALUES(9, randstr(1000,1000));
|
||||
COMMIT
|
||||
}
|
||||
} {1 {unable to open database file}}
|
||||
do_test io-2.6.3 {
|
||||
file delete -force test.db-journal
|
||||
catchsql { COMMIT }
|
||||
} {1 {cannot commit - no transaction is active}}
|
||||
} {0 {}}
|
||||
do_test io-2.6.4 {
|
||||
execsql { SELECT * FROM abc }
|
||||
} {1 2 3 4 5 6 7 8}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user