mirror of
https://github.com/status-im/sqlcipher.git
synced 2025-02-23 17:28:17 +00:00
Merge branch 'sqlite-release' into integration
Conflicts: Makefile.in test/quick.test
This commit is contained in:
commit
29b781102a
351
Makefile.in
351
Makefile.in
@ -171,31 +171,35 @@ NAWK = @AWK@
|
||||
# You should not have to change anything below this line
|
||||
###############################################################################
|
||||
|
||||
USE_AMALGAMATION = @USE_AMALGAMATION@
|
||||
|
||||
# Object files for the SQLite library (non-amalgamation).
|
||||
#
|
||||
OBJS0 = alter.lo analyze.lo attach.lo auth.lo backup.lo bitvec.lo btmutex.lo \
|
||||
btree.lo build.lo callback.lo complete.lo ctime.lo date.lo \
|
||||
delete.lo expr.lo fault.lo fkey.lo func.lo global.lo \
|
||||
hash.lo journal.lo insert.lo legacy.lo loadext.lo \
|
||||
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
|
||||
memjournal.lo \
|
||||
mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
|
||||
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo select.lo status.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 $(CRYPTOLIBOBJ)
|
||||
LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
|
||||
callback.lo complete.lo ctime.lo date.lo delete.lo expr.lo fault.lo fkey.lo \
|
||||
fts3.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo fts3_porter.lo \
|
||||
fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo fts3_write.lo \
|
||||
func.lo global.lo hash.lo \
|
||||
icu.lo insert.lo journal.lo legacy.lo loadext.lo \
|
||||
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
|
||||
memjournal.lo \
|
||||
mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \
|
||||
notify.lo opcodes.lo os.lo os_os2.lo os_unix.lo os_win.lo \
|
||||
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo select.lo status.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 \
|
||||
wal.lo walker.lo where.lo utf.o vtab.lo $(CRYPTOLIBOBJ)
|
||||
|
||||
# Object files for the amalgamation.
|
||||
#
|
||||
OBJS1 = sqlite3.lo
|
||||
LIBOBJS1 = sqlite3.lo
|
||||
|
||||
# Determine the real value of LIBOBJ based on the 'configure' script
|
||||
#
|
||||
USE_AMALGAMATION = @USE_AMALGAMATION@
|
||||
LIBOBJ = $(OBJS$(USE_AMALGAMATION))
|
||||
LIBOBJ = $(LIBOBJS$(USE_AMALGAMATION))
|
||||
|
||||
|
||||
# All of the source code files.
|
||||
@ -287,20 +291,11 @@ 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
|
||||
|
||||
# Generated source code files
|
||||
#
|
||||
SRC += \
|
||||
keywordhash.h \
|
||||
opcodes.c \
|
||||
opcodes.h \
|
||||
parse.c \
|
||||
parse.h \
|
||||
config.h \
|
||||
sqlite3.h
|
||||
|
||||
# Source code for extensions
|
||||
#
|
||||
SRC += \
|
||||
@ -342,44 +337,19 @@ SRC += \
|
||||
$(TOP)/ext/rtree/rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.c
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
#
|
||||
TESTSRC2 = \
|
||||
$(TOP)/src/attach.c \
|
||||
$(TOP)/src/backup.c \
|
||||
$(TOP)/src/bitvec.c \
|
||||
$(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/expr.c \
|
||||
$(TOP)/src/func.c \
|
||||
$(TOP)/src/insert.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/pcache.c \
|
||||
$(TOP)/src/pcache1.c \
|
||||
$(TOP)/src/pragma.c \
|
||||
$(TOP)/src/prepare.c \
|
||||
$(TOP)/src/printf.c \
|
||||
$(TOP)/src/random.c \
|
||||
$(TOP)/src/select.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/util.c \
|
||||
$(TOP)/src/vdbe.c \
|
||||
$(TOP)/src/vdbeapi.c \
|
||||
$(TOP)/src/vdbeaux.c \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/where.c \
|
||||
parse.c
|
||||
|
||||
# Source code to the actual test files.
|
||||
# Generated source code files
|
||||
#
|
||||
SRC += \
|
||||
keywordhash.h \
|
||||
opcodes.c \
|
||||
opcodes.h \
|
||||
parse.c \
|
||||
parse.h \
|
||||
config.h \
|
||||
sqlite3.h
|
||||
|
||||
# Source code to the test files.
|
||||
#
|
||||
TESTSRC = \
|
||||
$(TOP)/src/test1.c \
|
||||
@ -396,6 +366,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 \
|
||||
@ -409,60 +380,98 @@ TESTSRC = \
|
||||
$(TOP)/src/test_pcache.c \
|
||||
$(TOP)/src/test_schema.c \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_stat.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_wsd.c
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
#
|
||||
TESTSRC2 = \
|
||||
$(TOP)/src/attach.c \
|
||||
$(TOP)/src/backup.c \
|
||||
$(TOP)/src/bitvec.c \
|
||||
$(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c \
|
||||
$(TOP)/src/ctime.c \
|
||||
$(TOP)/src/date.c \
|
||||
$(TOP)/src/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 \
|
||||
$(TOP)/src/pcache1.c \
|
||||
$(TOP)/src/select.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/util.c \
|
||||
$(TOP)/src/vdbeapi.c \
|
||||
$(TOP)/src/vdbeaux.c \
|
||||
$(TOP)/src/vdbe.c \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/where.c \
|
||||
parse.c \
|
||||
$(TOP)/ext/fts3/fts3.c \
|
||||
$(TOP)/ext/fts3/fts3_expr.c \
|
||||
$(TOP)/ext/fts3/fts3_tokenizer.c \
|
||||
$(TOP)/ext/fts3/fts3_write.c \
|
||||
$(TOP)/ext/async/sqlite3async.c
|
||||
|
||||
# Header files used by all library source files.
|
||||
#
|
||||
HDR = \
|
||||
sqlite3.h \
|
||||
$(TOP)/src/btree.h \
|
||||
$(TOP)/src/btreeInt.h \
|
||||
$(TOP)/src/hash.h \
|
||||
$(TOP)/src/hwtime.h \
|
||||
$(TOP)/src/sqliteLimit.h \
|
||||
keywordhash.h \
|
||||
$(TOP)/src/mutex.h \
|
||||
opcodes.h \
|
||||
$(TOP)/src/os.h \
|
||||
$(TOP)/src/os_common.h \
|
||||
$(TOP)/src/pager.h \
|
||||
$(TOP)/src/pcache.h \
|
||||
parse.h \
|
||||
sqlite3.h \
|
||||
$(TOP)/src/sqlite3ext.h \
|
||||
$(TOP)/src/sqliteInt.h \
|
||||
$(TOP)/src/sqliteLimit.h \
|
||||
$(TOP)/src/vdbe.h \
|
||||
$(TOP)/src/vdbeInt.h \
|
||||
parse.h \
|
||||
config.h
|
||||
|
||||
# Header files used by extensions
|
||||
#
|
||||
HDR += \
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/fts1/fts1.h \
|
||||
$(TOP)/ext/fts1/fts1_hash.h \
|
||||
$(TOP)/ext/fts1/fts1_tokenizer.h
|
||||
HDR += \
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/fts2/fts2.h \
|
||||
$(TOP)/ext/fts2/fts2_hash.h \
|
||||
$(TOP)/ext/fts2/fts2_tokenizer.h
|
||||
HDR += \
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/fts3/fts3.h \
|
||||
$(TOP)/ext/fts3/fts3Int.h \
|
||||
$(TOP)/ext/fts3/fts3_hash.h \
|
||||
$(TOP)/ext/fts3/fts3_tokenizer.h
|
||||
HDR += \
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/rtree/rtree.h
|
||||
HDR += \
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/icu/sqliteicu.h
|
||||
|
||||
# If using the amalgamation, use sqlite3.c directly to build the test
|
||||
# fixture. Otherwise link against libsqlite3.la. (This distinction is
|
||||
# necessary because the test fixture requires non-API symbols which are
|
||||
# hidden when the library is built via the amalgamation).
|
||||
#
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
|
||||
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
#
|
||||
@ -496,10 +505,10 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
|
||||
# files are automatically generated. This target takes care of
|
||||
# all that automatic generation.
|
||||
#
|
||||
.target_source: $(SRC)
|
||||
.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl
|
||||
rm -rf tsrc
|
||||
mkdir -p tsrc
|
||||
cp $(SRC) tsrc
|
||||
mkdir tsrc
|
||||
cp -f $(SRC) tsrc
|
||||
rm tsrc/sqlite.h.in tsrc/parse.y
|
||||
$(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new
|
||||
mv vdbe.new tsrc/vdbe.c
|
||||
@ -508,24 +517,35 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
|
||||
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl
|
||||
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl
|
||||
|
||||
# Rule to build the amalgamation
|
||||
#
|
||||
sqlite3.lo: sqlite3.c
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c sqlite3.c
|
||||
|
||||
# Rules to build the LEMON compiler generator
|
||||
#
|
||||
lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/src/lempar.c
|
||||
$(BCC) -o $@ $(TOP)/tool/lemon.c
|
||||
cp $(TOP)/src/lempar.c .
|
||||
|
||||
|
||||
# Rule to build the amalgamation
|
||||
# Rules to build individual *.o files from generated *.c files. This
|
||||
# applies to:
|
||||
#
|
||||
sqlite3.lo: sqlite3.c
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c sqlite3.c
|
||||
# parse.o
|
||||
# opcodes.o
|
||||
#
|
||||
parse.lo: parse.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c parse.c
|
||||
|
||||
opcodes.lo: opcodes.c
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c opcodes.c
|
||||
|
||||
# BEGIN CRYPTO
|
||||
crypto.lo: $(TOP)/src/crypto.c $(HDR)
|
||||
$(LTCOMPILE) -c $(TOP)/src/crypto.c
|
||||
# END CRYPTO
|
||||
|
||||
# Rules to build individual files
|
||||
# Rules to build individual *.o files from files in the src directory.
|
||||
#
|
||||
alter.lo: $(TOP)/src/alter.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/alter.c
|
||||
@ -650,15 +670,6 @@ pcache.lo: $(TOP)/src/pcache.c $(HDR) $(TOP)/src/pcache.h
|
||||
pcache1.lo: $(TOP)/src/pcache1.c $(HDR) $(TOP)/src/pcache.h
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pcache1.c
|
||||
|
||||
opcodes.lo: opcodes.c
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c opcodes.c
|
||||
|
||||
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
|
||||
sort -n -b -k 3 opcodes.h | $(NAWK) -f $(TOP)/mkopcodec.awk >opcodes.c
|
||||
|
||||
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
|
||||
cat parse.h $(TOP)/src/vdbe.c | $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h
|
||||
|
||||
os.lo: $(TOP)/src/os.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os.c
|
||||
|
||||
@ -671,17 +682,6 @@ os_win.lo: $(TOP)/src/os_win.c $(HDR)
|
||||
os_os2.lo: $(TOP)/src/os_os2.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os_os2.c
|
||||
|
||||
parse.lo: parse.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c parse.c
|
||||
|
||||
parse.h: parse.c
|
||||
|
||||
parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk
|
||||
cp $(TOP)/src/parse.y .
|
||||
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
mv parse.h parse.h.temp
|
||||
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
|
||||
|
||||
pragma.lo: $(TOP)/src/pragma.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pragma.c
|
||||
|
||||
@ -706,22 +706,12 @@ select.lo: $(TOP)/src/select.c $(HDR)
|
||||
status.lo: $(TOP)/src/status.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/status.c
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
|
||||
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
|
||||
table.lo: $(TOP)/src/table.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c
|
||||
|
||||
tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c
|
||||
|
||||
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
|
||||
$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
|
||||
./mkkeywordhash$(BEXE) >keywordhash.h
|
||||
|
||||
trigger.lo: $(TOP)/src/trigger.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/trigger.c
|
||||
|
||||
@ -758,12 +748,18 @@ 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
|
||||
|
||||
where.lo: $(TOP)/src/where.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/where.c
|
||||
|
||||
tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DTCLSH=1 -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
@ -774,16 +770,113 @@ tclsqlite3$(TEXE): tclsqlite-shell.lo libsqlite3.la
|
||||
$(LTLINK) -o $@ tclsqlite-shell.lo \
|
||||
libsqlite3.la $(LIBTCL)
|
||||
|
||||
# Rules to build opcodes.c and opcodes.h
|
||||
#
|
||||
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
|
||||
sort -n -b -k 3 opcodes.h | $(NAWK) -f $(TOP)/mkopcodec.awk >opcodes.c
|
||||
|
||||
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
|
||||
cat parse.h $(TOP)/src/vdbe.c | $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h
|
||||
|
||||
# Rules to build parse.c and parse.h - the outputs of lemon.
|
||||
#
|
||||
parse.h: parse.c
|
||||
|
||||
parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk
|
||||
cp $(TOP)/src/parse.y .
|
||||
rm -f parse.h
|
||||
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
mv parse.h parse.h.temp
|
||||
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
|
||||
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
|
||||
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
|
||||
$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
|
||||
./mkkeywordhash$(BEXE) >keywordhash.h
|
||||
|
||||
|
||||
|
||||
# Rules to build the extension objects.
|
||||
#
|
||||
icu.lo: $(TOP)/ext/icu/icu.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/icu/icu.c
|
||||
|
||||
fts2.lo: $(TOP)/ext/fts2/fts2.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2.c
|
||||
|
||||
fts2_hash.lo: $(TOP)/ext/fts2/fts2_hash.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_hash.c
|
||||
|
||||
fts2_icu.lo: $(TOP)/ext/fts2/fts2_icu.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_icu.c
|
||||
|
||||
fts2_porter.lo: $(TOP)/ext/fts2/fts2_porter.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_porter.c
|
||||
|
||||
fts2_tokenizer.lo: $(TOP)/ext/fts2/fts2_tokenizer.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer.c
|
||||
|
||||
fts2_tokenizer1.lo: $(TOP)/ext/fts2/fts2_tokenizer1.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer1.c
|
||||
|
||||
fts3.lo: $(TOP)/ext/fts3/fts3.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3.c
|
||||
|
||||
fts3_expr.lo: $(TOP)/ext/fts3/fts3_expr.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_expr.c
|
||||
|
||||
fts3_hash.lo: $(TOP)/ext/fts3/fts3_hash.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_hash.c
|
||||
|
||||
fts3_icu.lo: $(TOP)/ext/fts3/fts3_icu.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_icu.c
|
||||
|
||||
fts3_snippet.lo: $(TOP)/ext/fts3/fts3_snippet.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_snippet.c
|
||||
|
||||
fts3_porter.lo: $(TOP)/ext/fts3/fts3_porter.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter.c
|
||||
|
||||
fts3_tokenizer.lo: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c
|
||||
|
||||
fts3_tokenizer1.lo: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c
|
||||
|
||||
fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c
|
||||
|
||||
rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
|
||||
|
||||
|
||||
# Rules to build the 'testfixture' application.
|
||||
#
|
||||
# If using the amalgamation, use sqlite3.c directly to build the test
|
||||
# fixture. Otherwise link against libsqlite3.la. (This distinction is
|
||||
# necessary because the test fixture requires non-API symbols which are
|
||||
# hidden when the library is built via the amalgamation).
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
|
||||
|
||||
testfixture$(TEXE): $(TESTFIXTURE_SRC)
|
||||
$(LTLINK) -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_NO_SYNC=1\
|
||||
-DSQLITE_CRASH_TEST=1 \
|
||||
-DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE $(TEMP_STORE) \
|
||||
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
|
||||
-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
|
||||
|
||||
|
||||
fulltest: testfixture$(TEXE) sqlite3$(TEXE)
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test
|
||||
|
||||
soaktest: testfixture$(TEXE) sqlite3$(TEXE)
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test -soak=1
|
||||
|
||||
test: testfixture$(TEXE) sqlite3$(TEXE)
|
||||
./testfixture$(TEXE) $(TOP)/test/veryquick.test
|
||||
|
||||
@ -797,9 +890,11 @@ sqlite3_analyzer$(TEXE): $(TESTFIXTURE_SRC) $(TOP)/tool/spaceanal.tcl
|
||||
$(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
|
||||
$(LTLINK) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 \
|
||||
-DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE \
|
||||
$(TEMP_STORE) -o $@ $(TESTFIXTURE_SRC) $(LIBTCL)
|
||||
$(TEMP_STORE) -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
|
||||
|
||||
|
||||
# Standard install and cleanup targets
|
||||
#
|
||||
lib_install: libsqlite3.la
|
||||
$(INSTALL) -d $(DESTDIR)$(libdir)
|
||||
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
|
||||
@ -824,15 +919,15 @@ tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
|
||||
clean:
|
||||
rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
|
||||
rm -f sqlite3.h opcodes.*
|
||||
rm -rf .libs .deps tsrc
|
||||
rm -rf .libs .deps
|
||||
rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
|
||||
rm -f mkkeywordhash$(BEXE) keywordhash.h
|
||||
rm -f $(PUBLISH)
|
||||
rm -f *.da *.bb *.bbg gmon.out
|
||||
rm -rf tsrc .target_source
|
||||
rm -f testfixture$(TEXE) test.db
|
||||
rm -f common.tcl
|
||||
rm -f sqlite3.dll sqlite3.lib sqlite3.def
|
||||
rm -f sqlite3.c .target_source
|
||||
rm -f sqlite3.c
|
||||
|
||||
distclean: clean
|
||||
rm -f config.log config.status libtool Makefile sqlite3.pc
|
||||
|
@ -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
|
||||
@ -624,7 +625,7 @@ fulltest: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/all.test
|
||||
|
||||
soaktest: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/all.test -soak 1
|
||||
./testfixture$(EXE) $(TOP)/test/all.test -soak=1
|
||||
|
||||
test: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/veryquick.test
|
||||
|
21
configure
vendored
21
configure
vendored
@ -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'
|
||||
|
@ -667,7 +667,7 @@ static int asyncRead(
|
||||
){
|
||||
AsyncFileData *p = ((AsyncFile *)pFile)->pData;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_int64 filesize;
|
||||
sqlite3_int64 filesize = 0;
|
||||
sqlite3_file *pBase = p->pBaseRead;
|
||||
sqlite3_int64 iAmt64 = (sqlite3_int64)iAmt;
|
||||
|
||||
@ -690,7 +690,7 @@ static int asyncRead(
|
||||
}
|
||||
nRead = MIN(filesize - iOffset, iAmt64);
|
||||
if( nRead>0 ){
|
||||
rc = pBase->pMethods->xRead(pBase, zOut, nRead, iOffset);
|
||||
rc = pBase->pMethods->xRead(pBase, zOut, (int)nRead, iOffset);
|
||||
ASYNC_TRACE(("READ %s %d bytes at %d\n", p->zName, nRead, iOffset));
|
||||
}
|
||||
}
|
||||
@ -717,9 +717,11 @@ static int asyncRead(
|
||||
if( iBeginIn<0 ) iBeginIn = 0;
|
||||
if( iBeginOut<0 ) iBeginOut = 0;
|
||||
|
||||
filesize = MAX(filesize, pWrite->iOffset+nByte64);
|
||||
|
||||
nCopy = MIN(nByte64-iBeginIn, iAmt64-iBeginOut);
|
||||
if( nCopy>0 ){
|
||||
memcpy(&((char *)zOut)[iBeginOut], &pWrite->zBuf[iBeginIn], nCopy);
|
||||
memcpy(&((char *)zOut)[iBeginOut], &pWrite->zBuf[iBeginIn], (size_t)nCopy);
|
||||
ASYNC_TRACE(("OVERREAD %d bytes at %d\n", nCopy, iBeginOut+iOffset));
|
||||
}
|
||||
}
|
||||
@ -728,6 +730,9 @@ static int asyncRead(
|
||||
|
||||
asyncread_out:
|
||||
async_mutex_leave(ASYNC_MUTEX_QUEUE);
|
||||
if( rc==SQLITE_OK && filesize<(iOffset+iAmt) ){
|
||||
rc = SQLITE_IOERR_SHORT_READ;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1138,7 +1143,6 @@ static int asyncOpen(
|
||||
async_mutex_leave(ASYNC_MUTEX_LOCK);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
incrOpenFileCount();
|
||||
pData->pLock = pLock;
|
||||
}
|
||||
|
||||
@ -1155,7 +1159,10 @@ static int asyncOpen(
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
p->pMethod = 0;
|
||||
}else{
|
||||
incrOpenFileCount();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1232,7 +1239,7 @@ static int asyncFullPathname(
|
||||
if( rc==SQLITE_OK ){
|
||||
int i, j;
|
||||
char *z = zPathOut;
|
||||
int n = strlen(z);
|
||||
int n = (int)strlen(z);
|
||||
while( n>1 && z[n-1]=='/' ){ n--; }
|
||||
for(i=j=0; i<n; i++){
|
||||
if( z[i]=='/' ){
|
||||
|
343
ext/fts3/fts3.c
343
ext/fts3/fts3.c
@ -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 */
|
||||
@ -604,6 +607,9 @@ static int fts3CreateTables(Fts3Table *p){
|
||||
** An sqlite3_exec() callback for fts3TableExists.
|
||||
*/
|
||||
static int fts3TableExistsCallback(void *pArg, int n, char **pp1, char **pp2){
|
||||
UNUSED_PARAMETER(n);
|
||||
UNUSED_PARAMETER(pp1);
|
||||
UNUSED_PARAMETER(pp2);
|
||||
*(int*)pArg = 1;
|
||||
return 1;
|
||||
}
|
||||
@ -629,7 +635,7 @@ static void fts3TableExists(
|
||||
);
|
||||
rc = sqlite3_exec(db, zSql, fts3TableExistsCallback, &res, 0);
|
||||
sqlite3_free(zSql);
|
||||
*pResult = res & 0xff;
|
||||
*pResult = (u8)(res & 0xff);
|
||||
if( rc!=SQLITE_ABORT ) *pRc = rc;
|
||||
}
|
||||
|
||||
@ -639,7 +645,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 +664,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 +899,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 +930,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 +1077,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 +1091,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 +1116,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 +1155,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 +1211,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 +1227,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 +1268,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 +1278,7 @@ static void fts3PoslistMerge(
|
||||
}
|
||||
}
|
||||
|
||||
*p++ = '\0';
|
||||
*p++ = POS_END;
|
||||
*pp = p;
|
||||
*pp1 = p1 + 1;
|
||||
*pp2 = p2 + 1;
|
||||
@ -1236,11 +1301,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 +1318,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 +1575,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));
|
||||
@ -1554,10 +1621,58 @@ static int fts3DoclistMerge(
|
||||
typedef struct TermSelect TermSelect;
|
||||
struct TermSelect {
|
||||
int isReqPos;
|
||||
char *aOutput; /* Malloc'd output buffer */
|
||||
int nOutput; /* Size of output in bytes */
|
||||
char *aaOutput[16]; /* Malloc'd output buffer */
|
||||
int anOutput[16]; /* Size of output in bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
** Merge all doclists in the TermSelect.aaOutput[] array into a single
|
||||
** doclist stored in TermSelect.aaOutput[0]. If successful, delete all
|
||||
** other doclists (except the aaOutput[0] one) and return SQLITE_OK.
|
||||
**
|
||||
** If an OOM error occurs, return SQLITE_NOMEM. In this case it is
|
||||
** the responsibility of the caller to free any doclists left in the
|
||||
** TermSelect.aaOutput[] array.
|
||||
*/
|
||||
static int fts3TermSelectMerge(TermSelect *pTS){
|
||||
int mergetype = (pTS->isReqPos ? MERGE_POS_OR : MERGE_OR);
|
||||
char *aOut = 0;
|
||||
int nOut = 0;
|
||||
int i;
|
||||
|
||||
/* Loop through the doclists in the aaOutput[] array. Merge them all
|
||||
** into a single doclist.
|
||||
*/
|
||||
for(i=0; i<SizeofArray(pTS->aaOutput); i++){
|
||||
if( pTS->aaOutput[i] ){
|
||||
if( !aOut ){
|
||||
aOut = pTS->aaOutput[i];
|
||||
nOut = pTS->anOutput[i];
|
||||
pTS->aaOutput[0] = 0;
|
||||
}else{
|
||||
int nNew = nOut + pTS->anOutput[i];
|
||||
char *aNew = sqlite3_malloc(nNew);
|
||||
if( !aNew ){
|
||||
sqlite3_free(aOut);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
fts3DoclistMerge(mergetype, 0, 0,
|
||||
aNew, &nNew, pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut
|
||||
);
|
||||
sqlite3_free(pTS->aaOutput[i]);
|
||||
sqlite3_free(aOut);
|
||||
pTS->aaOutput[i] = 0;
|
||||
aOut = aNew;
|
||||
nOut = nNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTS->aaOutput[0] = aOut;
|
||||
pTS->anOutput[0] = nOut;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used as the sqlite3Fts3SegReaderIterate() callback when
|
||||
** querying the full-text index for a doclist associated with a term or
|
||||
@ -1572,38 +1687,63 @@ static int fts3TermSelectCb(
|
||||
int nDoclist
|
||||
){
|
||||
TermSelect *pTS = (TermSelect *)pContext;
|
||||
int nNew = pTS->nOutput + nDoclist;
|
||||
char *aNew = sqlite3_malloc(nNew);
|
||||
|
||||
UNUSED_PARAMETER(p);
|
||||
UNUSED_PARAMETER(zTerm);
|
||||
UNUSED_PARAMETER(nTerm);
|
||||
|
||||
if( !aNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
if( pTS->nOutput==0 ){
|
||||
if( pTS->aaOutput[0]==0 ){
|
||||
/* If this is the first term selected, copy the doclist to the output
|
||||
** buffer using memcpy(). TODO: Add a way to transfer control of the
|
||||
** aDoclist buffer from the caller so as to avoid the memcpy().
|
||||
*/
|
||||
memcpy(aNew, aDoclist, nDoclist);
|
||||
pTS->aaOutput[0] = sqlite3_malloc(nDoclist);
|
||||
pTS->anOutput[0] = nDoclist;
|
||||
if( pTS->aaOutput[0] ){
|
||||
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
|
||||
}else{
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}else{
|
||||
/* The output buffer is not empty. Merge doclist aDoclist with the
|
||||
** existing output. This can only happen with prefix-searches (as
|
||||
** searches for exact terms return exactly one doclist).
|
||||
*/
|
||||
int mergetype = (pTS->isReqPos ? MERGE_POS_OR : MERGE_OR);
|
||||
fts3DoclistMerge(mergetype, 0, 0,
|
||||
aNew, &nNew, pTS->aOutput, pTS->nOutput, aDoclist, nDoclist
|
||||
);
|
||||
char *aMerge = aDoclist;
|
||||
int nMerge = nDoclist;
|
||||
int iOut;
|
||||
|
||||
for(iOut=0; iOut<SizeofArray(pTS->aaOutput); iOut++){
|
||||
char *aNew;
|
||||
int nNew;
|
||||
if( pTS->aaOutput[iOut]==0 ){
|
||||
assert( iOut>0 );
|
||||
pTS->aaOutput[iOut] = aMerge;
|
||||
pTS->anOutput[iOut] = nMerge;
|
||||
break;
|
||||
}
|
||||
|
||||
nNew = nMerge + pTS->anOutput[iOut];
|
||||
aNew = sqlite3_malloc(nNew);
|
||||
if( !aNew ){
|
||||
if( aMerge!=aDoclist ){
|
||||
sqlite3_free(aMerge);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
fts3DoclistMerge(mergetype, 0, 0,
|
||||
aNew, &nNew, pTS->aaOutput[iOut], pTS->anOutput[iOut], aMerge, nMerge
|
||||
);
|
||||
|
||||
if( iOut>0 ) sqlite3_free(aMerge);
|
||||
sqlite3_free(pTS->aaOutput[iOut]);
|
||||
pTS->aaOutput[iOut] = 0;
|
||||
|
||||
aMerge = aNew;
|
||||
nMerge = nNew;
|
||||
if( (iOut+1)==SizeofArray(pTS->aaOutput) ){
|
||||
pTS->aaOutput[iOut] = aMerge;
|
||||
pTS->anOutput[iOut] = nMerge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(pTS->aOutput);
|
||||
pTS->aOutput = aNew;
|
||||
pTS->nOutput = nNew;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -1613,9 +1753,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(
|
||||
@ -1727,12 +1867,17 @@ static int fts3TermSelect(
|
||||
rc = sqlite3Fts3SegReaderIterate(p, apSegment, nSegment, &filter,
|
||||
fts3TermSelectCb, (void *)&tsc
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3TermSelectMerge(&tsc);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
*ppOut = tsc.aOutput;
|
||||
*pnOut = tsc.nOutput;
|
||||
*ppOut = tsc.aaOutput[0];
|
||||
*pnOut = tsc.anOutput[0];
|
||||
}else{
|
||||
sqlite3_free(tsc.aOutput);
|
||||
for(i=0; i<SizeofArray(tsc.aaOutput); i++){
|
||||
sqlite3_free(tsc.aaOutput[i]);
|
||||
}
|
||||
}
|
||||
|
||||
finished:
|
||||
@ -1875,7 +2020,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
|
||||
|
72
main.mk
72
main.mk
@ -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 \
|
||||
@ -244,26 +247,51 @@ TESTSRC = \
|
||||
$(TOP)/src/test_pcache.c \
|
||||
$(TOP)/src/test_schema.c \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_stat.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
|
||||
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c
|
||||
|
||||
TESTSRC2 = \
|
||||
$(TOP)/src/attach.c $(TOP)/src/backup.c $(TOP)/src/btree.c \
|
||||
$(TOP)/src/build.c $(TOP)/src/date.c \
|
||||
$(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.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 \
|
||||
$(TOP)/src/pcache1.c $(TOP)/src/select.c $(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/utf.c $(TOP)/src/util.c $(TOP)/src/vdbeapi.c $(TOP)/src/vdbeaux.c \
|
||||
$(TOP)/src/vdbe.c $(TOP)/src/vdbemem.c $(TOP)/src/where.c parse.c \
|
||||
$(TOP)/ext/fts3/fts3.c $(TOP)/ext/fts3/fts3_expr.c \
|
||||
$(TOP)/ext/fts3/fts3_tokenizer.c $(TOP)/ext/fts3/fts3_write.c \
|
||||
$(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/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 \
|
||||
$(TOP)/src/pcache1.c \
|
||||
$(TOP)/src/select.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/util.c \
|
||||
$(TOP)/src/vdbeapi.c \
|
||||
$(TOP)/src/vdbeaux.c \
|
||||
$(TOP)/src/vdbe.c \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/where.c \
|
||||
parse.c \
|
||||
$(TOP)/ext/fts3/fts3.c \
|
||||
$(TOP)/ext/fts3/fts3_expr.c \
|
||||
$(TOP)/ext/fts3/fts3_tokenizer.c \
|
||||
$(TOP)/ext/fts3/fts3_write.c \
|
||||
$(TOP)/ext/async/sqlite3async.c
|
||||
|
||||
# Header files used by all library source files.
|
||||
@ -322,8 +350,6 @@ sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
|
||||
$(TOP)/src/shell.c \
|
||||
libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
|
||||
|
||||
objects: $(LIBOBJ_ORIG)
|
||||
|
||||
# This target creates a directory named "tsrc" and fills it with
|
||||
# copies of all of the C source code and header files needed to
|
||||
# build on the target system. Some of the C source code and header
|
||||
@ -393,7 +419,7 @@ parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
|
||||
rm -f parse.h
|
||||
./lemon $(OPTS) parse.y
|
||||
mv parse.h parse.h.temp
|
||||
awk -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
|
||||
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
|
||||
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
@ -467,21 +493,21 @@ tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a
|
||||
|
||||
# Rules to build the 'testfixture' application.
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
|
||||
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
|
||||
$(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \
|
||||
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB) libsqlite3.a
|
||||
|
||||
amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
|
||||
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \
|
||||
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
|
||||
|
||||
fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
|
||||
-DSQLITE_ENABLE_FTS3=1 \
|
||||
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \
|
||||
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
|
||||
@ -490,7 +516,7 @@ fulltest: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/all.test
|
||||
|
||||
soaktest: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/all.test -soak 1
|
||||
./testfixture$(EXE) $(TOP)/test/all.test -soak=1
|
||||
|
||||
test: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/veryquick.test
|
||||
@ -504,8 +530,8 @@ sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c sqlite3.c $(TESTSRC) \
|
||||
-e 's,^,",' \
|
||||
-e 's,$$,\\n",' \
|
||||
$(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
|
||||
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
|
||||
-DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_DEBUG=1 -DSQLITE_PRIVATE="" \
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=2 $(TESTFIXTURE_FLAGS) \
|
||||
-DSQLITE_TEST=1 -DSQLITE_PRIVATE="" \
|
||||
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \
|
||||
-o sqlite3_analyzer$(EXE) \
|
||||
$(LIBTCL) $(THREADLIB)
|
||||
|
465
manifest
465
manifest
@ -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 Fix\sa\scomment\stypo.\s\sThis\scheck-in\sis\s3.7.0\srelease\scandidate\s2.
|
||||
D 2010-07-21T16:16:28
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
|
||||
F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
F Makefile.vxworks ab005d301296c40e021ccd0133ce49ca811e319f
|
||||
F Makefile.vxworks 4314cde20a1d9460ec5083526ea975442306ae7e
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 09d2dfb6a4a47d07b3b2091e349eedef78fb0f77
|
||||
F VERSION 4dce4379514b12d6bc5c30f7d1f64582ccb4f412
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
|
||||
@ -18,17 +18,21 @@ F art/SQLiteLogo3.tiff b9e6bf022ae939bc986cddb8ab99583ca1b02cb3
|
||||
F art/SQLite_big.gif 2b8e4603b91ba2a2c7062a82ff570d945034bb30
|
||||
F art/nocopy.gif 716aa07d4bb7250d4e75756073bf8ef9f56bec8f
|
||||
F art/powered_by_sqlite.gif 7fbcd7d3675391fd3d21672c14c05f5999eb60d1
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
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
|
||||
F ext/async/sqlite3async.c a7c6078c82c0bac3b7bea95bc52d5ce7ed58083a
|
||||
F ext/async/sqlite3async.h a21e1252deb14a2c211f0e165c4b9122a8f1f344
|
||||
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
|
||||
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
|
||||
@ -59,15 +63,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 9dec342fa1cf0914da679a3b7c0d4b53a27883ba
|
||||
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 +81,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,156 +94,161 @@ 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 26ad86cf0689940f19b3d608bbfdb3956b2fb9a7
|
||||
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 3457a2af126eb78f20ad239c225a2c8ed61b78b6
|
||||
F src/attach.c 17bec1f18254d9341369f20f90ba24ce35d20d10
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c b293534bc2df23c57668a585b17ee7faaaef0939
|
||||
F src/backup.c 51d83300fe0baee39405c416ceb19a58ed30a8ed
|
||||
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/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7
|
||||
F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
|
||||
F src/btree.c 9a214e6141555b183216b73ace058c7a499cdbe2
|
||||
F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
|
||||
F src/btreeInt.h b0c87f6725b06a0aa194a6d25d54b16ce9d6e291
|
||||
F src/build.c 559d38b48f79bc92370c082f4606eefe1e8f94ac
|
||||
F src/callback.c 01843bdf4b0420fd28046525d150fcd9802931a9
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c ceb247eb31620bba66a94c3f697db489a1652353
|
||||
F src/date.c 485a4409a384310e6d93fd1104a9d0a8658becd9
|
||||
F src/delete.c 610dc008e88a9599f905f5cbe9577ac9c36e0581
|
||||
F src/expr.c 6baed2a0448d494233d9c0a610eea018ab386a32
|
||||
F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
|
||||
F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
|
||||
F src/delete.c 41cb4f78557810eecc167b7e2317de7e12d20929
|
||||
F src/expr.c b2b053429575bf964c64bdf5459c5cbbe5bf93b8
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
|
||||
F src/func.c 5dca069d98eca0ff70c9a8fb8ab9e1d6467187b5
|
||||
F src/global.c 5a9c1e3c93213ca574786ac1caa976ce8f709105
|
||||
F src/func.c 0c28599430856631216b6c0131c51c89bf516026
|
||||
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 76d6b44a9f9050134fd81205f4b792cbdac7c925
|
||||
F src/journal.c b0ea6b70b532961118ab70301c00a33089f9315c
|
||||
F src/insert.c d9476f23f85a20eea3cc25a4b9f9cbae77a33bf2
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
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 a487fe90aecaccb142e4a6b738c7e26e99145bcd
|
||||
F src/malloc.c 09c3777bf733a387bec6aa344e455eb4e8ecf47e
|
||||
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 4a93a25ad9f76c40afa070ffd7187eb3a5fd7aee
|
||||
F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f
|
||||
F src/mutex.h 6fde601e55fa6c3fae768783c439797ab84c87c6
|
||||
F src/mutex_noop.c 5f58eaa31f2d742cb8957a747f7887ae98f16053
|
||||
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/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||
F src/pcache.c 4956b41d6ba913f7a8a56fbf32be78caed0e45c2
|
||||
F src/mutex_noop.c d5cfbca87168c661a0b118cd8e329a908e453151
|
||||
F src/mutex_os2.c 6a62583e374ba3ac1a3fcc0da2bfdac7d3942689
|
||||
F src/mutex_unix.c cf84466b4fdd2baa0d5a10bb19f08b2abc1ce42e
|
||||
F src/mutex_w32.c 1fe0e735897be20e09dd6f53c3fb516c6b48c0eb
|
||||
F src/notify.c cbfa66a836da3a51567209636e6a94059c137930
|
||||
F src/os.c 60178f518c4d6c0dcb59f7292232281d7bea2dcf
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19
|
||||
F src/os_unix.c 3109e0e5a0d5551bab2e8c7322b20a3b8b171248
|
||||
F src/os_win.c 1f8b0a1a5bcf6289e7754d0d3c16cec16d4c93ab
|
||||
F src/pager.c 78ca1e1f3315c8227431c403c04d791dccf242fb
|
||||
F src/pager.h 879fdde5a102d2f21a3135d6f647530b21c2796c
|
||||
F src/parse.y 220a11ac72e2c9dffbf4cbe5fe462f328bd8d884
|
||||
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 2bb2261190b42a348038f5b1c285c8cef415fcc8
|
||||
F src/pragma.c 56d95f76154a5f873c32eae485bb625f3c70be46
|
||||
F src/prepare.c 18292e5f365655cd5c5693e09508e90668f7d547
|
||||
F src/pcache1.c 3a7c28f46a61b43ff0b5c087a7983c154f4b264c
|
||||
F src/pragma.c 4a79269ea6f86150fb8e44688c753989fc7238dd
|
||||
F src/prepare.c f045aeff869d6409a2eae2fe08f7dc2df9528195
|
||||
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c a1648d98e869937b29f4f697461fe4d60f220a7b
|
||||
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
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 4903ff1bbd08b55cbce00ea43c645530de41b362
|
||||
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
|
||||
F src/sqlite.h.in 8b05aef506d9bc7fc7da1572744e3174cb16ed59
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h 6873f7f4c24fcdceece8777f2a1cbec049df77a0
|
||||
F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
|
||||
F src/status.c d329385a2cba3ea49d9d68af0ad84b22d46b4f40
|
||||
F src/sqliteInt.h d9e42f2029d4c526f9ba960bda1980ef17429c30
|
||||
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 ae1e4fb653c91ddad7e2534d209711a12604ccc4
|
||||
F src/test1.c ff3b4533fc4d78d1bff2ef831a5791db55096ed3
|
||||
F src/test2.c e3f564ab1e9fd0b47b0c9e23e7054e38bf0836cf
|
||||
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
|
||||
F src/test4.c ad03bb987ddedce928f4258c1e7fa4109a73497d
|
||||
F src/test5.c cc55900118fa4add8ec9cf69fc4225a4662f76b1
|
||||
F src/test6.c a8ece4284d0e34477f349ac05655db73c48e0926
|
||||
F src/test6.c c7256cc21d2409486d094277d5b017e8eced44ba
|
||||
F src/test7.c 3f2d63e4ccf97f8c2cf1a7fa0a3c8e2e2a354e6e
|
||||
F src/test8.c f959db9a22d882013b64c92753fa793b2ce3bdea
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c c1656facbaf43cb2e71b62621e5b9eb080e2621c
|
||||
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
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 5a11c51af2156e2d07186930b36f2b8239a4393f
|
||||
F src/test_demovfs.c da81a5f7785bb352bda7911c332a983ec4f17f27
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
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 424a334cdfdc8a6f975abe3641440147bded3185
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c f777d15df756bea0e98271932464ac5d882e66fe
|
||||
F src/test_malloc.c 4ab85f2b8ae3a237f4e6557b0a641181a19ffab1
|
||||
F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
|
||||
F src/test_onefile.c 06da7e085dce42924cf062b91763dd4bb84c6101
|
||||
F src/test_osinst.c 90fb03d396f39956897dfb4bd0e62c6711db1cca
|
||||
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
|
||||
F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
|
||||
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_stat.c 6ebaf2a86d01ccda24e49c148f1d33e8badda06e
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 00fed80690ae7f1525483a35861511c48bc579f2
|
||||
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
|
||||
F src/test_vfs.c 7e291f85256516ebde6633bc381ff7eedfa30234
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||
F src/trigger.c 340c9eca0fb24b1197468d96ba059f867c9834c7
|
||||
F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
|
||||
F src/trigger.c 67e95c76d625b92d43409ace771c8e0d02a09ac2
|
||||
F src/update.c 19c899c23cd29fd102c9068e0b0ff5b087204beb
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||
F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee
|
||||
F src/vdbe.c 8acca6dab2505e9650f6f014ada6ef30570cba99
|
||||
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
|
||||
F src/vdbe.c 6294de3327e09d14e9c06ecfd10e57c2d8e85307
|
||||
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
|
||||
F src/vdbeInt.h ae1e6ba0dd3fb4a886898d2829d748be701b01f8
|
||||
F src/vdbeapi.c 74c25680046a116b24b95393914d3669c23305dc
|
||||
F src/vdbeaux.c 0f352f63be78138bd94275aa3c8361e760ecc639
|
||||
F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
|
||||
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
|
||||
F src/vdbeaux.c 7f99c1f00e4b31e8b28d8a87ecc2322bb46ae99c
|
||||
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
|
||||
F src/vdbemem.c 5e579abf6532001dfbee0e640dc34eae897a9807
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c 606adf51cd6d4ba51a8c6dccede06a6f7b0dd72d
|
||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||
F src/wal.c 0925601f3299c2941a67c9cfff41ee710f70ca82
|
||||
F src/wal.h 906c85760598b18584921fe08008435aa4eeeeb2
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 399ea4c090284c9d16f76d685b9b44e8b9b4442b
|
||||
F src/where.c 903a7828a0a7de03b5d0f1b5eff222d8d5b138f1
|
||||
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/all.test 6745008c144bd2956d58864d21f7b304689c1cce
|
||||
F test/alter.test 15f9224868b290d6bf7a63f31437f31aee070636
|
||||
F test/alter2.test 52096b711afe5f219e575c6db7a70f7a35df4f63
|
||||
F test/alter3.test 25b95a136708f22b87184fa6a4309eea03d65153
|
||||
F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test ad5329098fe4de4a96852231d53e3e9e6283ad4b
|
||||
F test/analyze2.test a2ad7b0a4e13801ee3968fe70f22aff52326569c
|
||||
F test/analyze.test bf692e7db414f268a136bade16c03a1bdbb9240c
|
||||
F test/analyze2.test 59dac6c399c0c5d1a90a11ee7cc606743fb6db93
|
||||
F test/analyze3.test 506203875258ffd8ffa879b9c3c5432022d2b6d8
|
||||
F test/async.test 8c75d31b8330f8b70cf2571b014d4476a063efdb
|
||||
F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
F test/async4.test aafa6328c559d3e4bb587de770cbdecfca06f0da
|
||||
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
|
||||
F test/async5.test f3592d79c84d6e83a5f50d3fd500445f7d97dfdf
|
||||
F test/attach.test ce9660e51768fab93cf129787be886c5d6c4fd81
|
||||
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
||||
@ -249,16 +258,17 @@ F test/auth.test 8f21c160a4562f54f27618e85bac869efcecbcaf
|
||||
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46
|
||||
F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
|
||||
F test/autoindex1.test ffb06a246e2c1f89cfbe3d93eca513c9e78d4063
|
||||
F test/autovacuum.test bb7c0885e6f8f1d633045de48f2b66082162766d
|
||||
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
|
||||
F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
|
||||
F test/backup.test 3549ea8f541a08205c0eb813b21e81ea8301f6ed
|
||||
F test/backup2.test 159419073d9769fdb1780ed7e5b391a046f898d5
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
F test/backup.test 200e64bd91244b73ca8094bc1e03dfc83cc94c2e
|
||||
F test/backup2.test b7c69f937c912e85ac8a5dbd1e1cf290302b2d49
|
||||
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
|
||||
F test/backup_malloc.test 1e063c6d75143d0d6e0ae77971dd690070369387
|
||||
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070
|
||||
F test/bigfile.test b746a34ce0e2039994b45fea8b7fbfa78f594cdf
|
||||
F test/bigfile.test a8ec8073a20207456dab01a29ad9cde42b0dd103
|
||||
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
|
||||
F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c
|
||||
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
|
||||
@ -273,11 +283,11 @@ F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45
|
||||
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/capi3.test 168e2cd66c58c510955b0f299750e4de73b8d952
|
||||
F test/capi3b.test 664eb55318132f292f2c436f90906f578cad6b97
|
||||
F test/capi3c.test 493385107dcedfaf4f2b1c3738c8c1fa00362006
|
||||
F test/cache.test c4288607b54f2702858492fc4b92828336a1812f
|
||||
F test/capi2.test 00032d7504b9c14f1b36331670c5e7b0f73e3c5d
|
||||
F test/capi3.test 1945a2ba75e3f4c49d5beb8fc092115b6292d471
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test bea67403a5e37a4b33230ee4723e315a2ffb31e7
|
||||
F test/capi3d.test 57d83b690d7364bde02cddbf8339a4b50d80ce23
|
||||
F test/cast.test 166951664a0b0a2e0f8fb5997a152490c6363932
|
||||
F test/check.test db2b29d557544347d28e25b8406f5d5ecc3d1bc3
|
||||
@ -285,7 +295,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
|
||||
@ -295,20 +305,20 @@ F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
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/corrupt3.test 263e8bb04e2728df832fddf6973cf54c91db0c32
|
||||
F test/corrupt4.test acdb01afaedf529004b70e55de1a6f5a05ae7fff
|
||||
F test/corrupt.test 1a5bef8b2d178859af69814ecedcd37219a89968
|
||||
F test/corrupt2.test 808a28d0ca3b97e9aa8c91cd2b485ea2700b76d1
|
||||
F test/corrupt3.test a399dacccb91c732f6b071c913e70d195af8c058
|
||||
F test/corrupt4.test b963f9e01e0f92d15c76fb0747876fd4b96dc30a
|
||||
F test/corrupt5.test c23da7bfb20917cc7fdbb13ee25c7cc4e9fffeff
|
||||
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/corruptC.test 691ed070baef5e1345939caadf270a52837a5064
|
||||
F test/corrupt6.test 4e4161aef1f30b9f34582bb4142334b7f47eacae
|
||||
F test/corrupt7.test a90caf89c7d7cb7893ea4d92529bd0c129317ee4
|
||||
F test/corrupt8.test 48eb37ffb9a03bceada62219e2bd4c92f4b0cb75
|
||||
F test/corrupt9.test fad0bc26a5c972580a8d763c62f24094f4e8ef25
|
||||
F test/corruptA.test 38b4f81c16099f6d8fa8b37e188fde76b8243994
|
||||
F test/corruptB.test 44133515cf46c4d7bba691e3bcfa478080413af0
|
||||
F test/corruptC.test 483aa35dadfd96bdf549e38d75ffc2942576477e
|
||||
F test/corruptD.test 3ae6e2dc6e2226c6935a8a40d4b5ee3eba75f8c0
|
||||
F test/corruptE.test dbf66cae4c0e977ca9625a9114cdd01df8967bef
|
||||
F test/corruptE.test 7290b61145d954be549340e462ca84826d8a31a3
|
||||
F test/count.test 454e1ce985c94d13efeac405ce54439f49336163
|
||||
F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89
|
||||
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
|
||||
@ -317,35 +327,37 @@ F test/crash4.test 02ff4f15c149ca1e88a5c299b4896c84d9450c3b
|
||||
F test/crash5.test 80a2f7073381837fc082435c97df52a830abcd80
|
||||
F test/crash6.test 9c730cf06335003cb1f5cfceddacd044155336e0
|
||||
F test/crash7.test e20a7b9ee1d16eaef7c94a4cb7ed2191b4d05970
|
||||
F test/crash8.test 3af0fc90c3e593b85e810b8d6c50fc7d0df30008
|
||||
F test/crash8.test 76b95451933fe172ce8e26bff22d5c663c8ae473
|
||||
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
||||
F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/ctime.test f5040beef89c1b2bdb6a9edb7358a519213ff80c
|
||||
F test/date.test 0b8473ed9ab6fd4283b4a01f035e1067762ba734
|
||||
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
|
||||
F test/date.test 6354b883f922c38046a8efbad187cc95df6da023
|
||||
F test/dbstatus.test 838447a0ecca1232675b025c0a518a9ef0f8057e
|
||||
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||
F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4
|
||||
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
||||
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
|
||||
F test/descidx1.test a13d443571e045b61b1b2b759df8dcffa092c968
|
||||
F test/descidx2.test 1310ed1326cdfed4ea2c55169631579f082d174f
|
||||
F test/descidx3.test 3394ad4d089335cac743c36a14129d6d931c316f
|
||||
F test/descidx1.test b1353c1a15cfbee97b13a1dcedaf0fe78163ba6a
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f
|
||||
F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_expr.test 141e53fea525bce4f5403fcb0067b88e64fec5eb
|
||||
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
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test 4d8a112d6c5bf52014e9383c25ff193cc4f67185
|
||||
F test/exclusive2.test 6bdf254770a843c2933b54bee9ed239934f0a183
|
||||
F test/exclusive.test 5fe18e10a159342dd52ca14b1554e33f98734267
|
||||
F test/exclusive2.test fcbb1c9ca9739292a0a22a3763243ad6d868086b
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
|
||||
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
|
||||
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
|
||||
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
|
||||
F test/filefmt.test 5d271bf467e6557fe7499dcc8203069c9dc5825e
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
F test/fkey2.test e71f5baf9bb42cdba4700d73cba6f4d82fd6b925
|
||||
F test/fkey2.test 098c06c139a79f690301a43511cd1f6420ae5433
|
||||
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
|
||||
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
@ -363,7 +375,7 @@ F test/fts1m.test 2d9ca67b095d49f037a914087cc0a61e89da4f0c
|
||||
F test/fts1n.test a2317dcd27b1d087ee3878b30e0a59c593c98b7a
|
||||
F test/fts1o.test 382b8b07a2d6de5610814d9477117c4430464b9c
|
||||
F test/fts1porter.test d86e9c3e0c7f8ff95add6582b4b585fb4e02b96d
|
||||
F test/fts2.test 2fcc0cfcda440f1eb23b5d7897a8ec7b55a02239
|
||||
F test/fts2.test e3fb95f96a650411574efc136f3fb10eef479ed7
|
||||
F test/fts2a.test 473a5c8b473a4e21a8e3fddaed1e59666e0c6ab7
|
||||
F test/fts2b.test 964abc0236c849c07ca1ae496bb25c268ae94816
|
||||
F test/fts2c.test ffb5a35230ac72c4354535c547965ce6824537c0
|
||||
@ -383,8 +395,8 @@ F test/fts2p.test 4b48c35c91e6a7dbf5ac8d1e5691823cc999aafb
|
||||
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.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
|
||||
F test/fts3_common.tcl 4d8eec9db565fed9098f45c378f28e1657802011
|
||||
F test/fts3aa.test 5327d4c1d9b6c61021696746cc9a6cdc5bf159c0
|
||||
F test/fts3ab.test 09aeaa162aee6513d9ff336b6932211008b9d1f9
|
||||
F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63
|
||||
@ -398,7 +410,7 @@ F test/fts3aj.test 584facbc9ac4381a7ec624bfde677340ffc2a5a4
|
||||
F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
||||
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
|
||||
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
|
||||
F test/fts3an.test 931fa21bd80641ca594bfa32e105250a8a07918b
|
||||
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
|
||||
F test/fts3ao.test 0aa29dd4fc1c8d46b1f7cfe5926f7ac97551bea9
|
||||
F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa
|
||||
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
|
||||
@ -410,34 +422,34 @@ 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
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/fuzz.test a4174c3009a3e2c2e14b31b364ebf7ddb49de2c9
|
||||
F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
|
||||
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/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
|
||||
F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a
|
||||
F test/icu.test 1fc0ff9a3bafc80abf679b11afc0f8a3ce995abd
|
||||
F test/in.test d49419c6df515852f477fa513f3317181d46bc92
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
|
||||
F test/incrblob.test 54ac96eacab29215f1e1513f3b6843ebd0242eac
|
||||
F test/incrblob.test e557f262cd2cc088e6bb4d154575a1bbe242edcd
|
||||
F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19
|
||||
F test/incrblob_err.test c577c91d4ed9e8336cdb188b15d6ee2a6fe9604e
|
||||
F test/incrvacuum.test d0fb6ef6d747ef5c5ebe878aafa72dd3e178856b
|
||||
F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462
|
||||
F test/incrvacuum2.test 9e22a794899c91b7d8c8e12eaacac8df249faafe
|
||||
F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291
|
||||
F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 727d55dceb9a4ec36675057bb5becfc265e28ca6
|
||||
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
|
||||
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 +458,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,8 +471,10 @@ 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/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd
|
||||
F test/journal2.test 50a3604768494d4a337f194f0a9480e7c57dcb72
|
||||
F test/journal3.test ff175219be1b02d2f7e54297ad7e491b7533edb6
|
||||
F test/jrnlmode.test 2d5a8b6d68de8512f522532731d90ca96912f3b7
|
||||
F test/jrnlmode2.test a19e28de1a6ec898067e46a122f1b71c9323bf00
|
||||
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
||||
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
||||
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
||||
@ -471,16 +485,17 @@ 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 5242d8ac4e2d59c403aebff606af449b455aceff
|
||||
F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00
|
||||
F test/lock4.test f4f36271aa5ae1da449646bf43c7341f6b2b4c4e
|
||||
F test/lock5.test 6b1f78f09ad1522843dad571b76b321e6f439bf7
|
||||
F test/lock6.test 862aa71e97b288d6b3f92ba3313f51bd0b003776
|
||||
F test/lock4.test c82268c031d39345d05efa672f80b025481b3ae5
|
||||
F test/lock5.test b2abb5e711bc59b0eae00f6c97a36ec9f458fada
|
||||
F test/lock6.test 8df56060f396151777390982422c800d026e1722
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lookaside.test 1dd350dc6dff015c47c07fcc5a727a72fc5bae02
|
||||
F test/main.test 2be2352ac77ac5b238c6337a5469aeeef57677e6
|
||||
F test/lock_common.tcl e7013c6208f5fa818735c324eb0249b4c0f317cf
|
||||
F test/lookaside.test 382e7bc2fab23d902c8eafb1b9ed7ababfff75a6
|
||||
F test/main.test 9d7bbfcc1b52c88ba7b2ba6554068ecf9939f252
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test d23580e15c33ee0353717129421b077541e910dc
|
||||
F test/malloc.test 927e6c8668a1d48c23aa6189bda02aff5a1b83de
|
||||
F test/malloc3.test 4bc57f850b212f706f3e1b37c4eced1d5a727cd1
|
||||
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
|
||||
F test/malloc5.test 4d16d1bb26d2deddd7c4f480deec341f9b2d0e22
|
||||
@ -489,87 +504,93 @@ F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
|
||||
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
|
||||
F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e
|
||||
F test/mallocA.test 4b650c745aab289079454f4d1c02abe5c97ab6b3
|
||||
F test/mallocAll.test 2a2222a5e447be6c6579055a9a26e507e4586f4e
|
||||
F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be
|
||||
F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6
|
||||
F test/mallocC.test 7fcfb7c6cab30dc90d0fe3f2d5e3bcda5de33761
|
||||
F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4
|
||||
F test/mallocD.test f78c295e8e18ea3029e65ca08278690e00c22100
|
||||
F test/mallocE.test db1ed69d7eded1b080952e2a7c37f364ad241b08
|
||||
F test/mallocF.test 2d5c590ebc2fc7f0dcebdf5aa8498b9aed69107e
|
||||
F test/mallocG.test 4584d0d8ddb8009f16ca0c8bab1fa37f6358efa2
|
||||
F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
||||
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
|
||||
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl 984baeb6c6b185e798827d1187d426acc2bc4962
|
||||
F test/malloc_common.tcl f4a04b7a733eb114a3da16eb39035cde2c851220
|
||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
|
||||
F test/memsubsys1.test fd8a33046b6e758e3eb93747dc4eec21fe56bf64
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test 8fb47b7e2523f94c100f5885c5697505524de4b9
|
||||
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/minmax3.test 66a60eb0f20281b0753249d347c5de0766954cee
|
||||
F test/misc1.test e56baf44656dd68d6475a4b44521045a60241e9b
|
||||
F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd
|
||||
F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6
|
||||
F test/misc4.test 91e8ed25c092c2bb4e0bb01864631e2930f8d7de
|
||||
F test/misc5.test 6a5c1e3217a95b0db05ff9a0f1ecb5ce9043ffef
|
||||
F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd
|
||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test c5f4e6a82e04e71820c0f9f64f6733f04c8ae0ae
|
||||
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
||||
F test/mutex1.test 5b71777fc127509cd257910c8db799de557a02de
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test cf555724e5a26aed2296a3f2637feee9f728cd81
|
||||
F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723
|
||||
F test/notify1.test 8433bc74bd952fb8a6e3f8d7a4c2b28dfd69e310
|
||||
F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db
|
||||
F test/notify3.test 7eeba3628c4e707c004b72a2489c48fbdbc5c2ee
|
||||
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
||||
F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
|
||||
F test/pager1.test d8e4b2bc8164c920e6ea0572c9e13576d6e4f3fa
|
||||
F test/pager2.test f5c757c271ce642d36a393ecbfb3aef1c240dcef
|
||||
F test/pagerfault.test a4c0bb8900b8dbf5fcbe41ee2a96148e22174bcb
|
||||
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
|
||||
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||
F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
|
||||
F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d
|
||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||
F test/permutations.test 91928573ca2db2c88dbc50ab34e4a585d912b580
|
||||
F test/pragma.test 5aeb48a442dba3c3e8e38773b121371814ab3b17
|
||||
F test/permutations.test 3fe47c21c32b294b2354e702a25bfbff65747bb1
|
||||
F test/pragma.test ed78d200f65c6998df51196cb8c39d5300570f24
|
||||
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 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
|
||||
F test/rdonly.test bd054831f8a3078e765a0657e247182486f0cb47
|
||||
F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/rollback.test 73355ad4492ff9a3a31e61c7e5eb5e01a1de94ca
|
||||
F test/rowhash.test 97f56043ba11f0679920416c0cdbc72e5272267b
|
||||
F test/rollback.test 1a83118ea6db4e7d8c10eaa63871b5e90502ffdc
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287
|
||||
F test/rtree.test 55466a200af3591946c5da77ad5dbfbc1e5e05f9
|
||||
F test/savepoint.test f2ede4b643ad87ead36c041c72d774a1f5c8a564
|
||||
F test/savepoint2.test 427c8b20f43d3edf17a290c6788ae9e2703ac51c
|
||||
F test/rtree.test fb372aff108d4371bd0b5e63e106947587ff4310
|
||||
F test/savepoint.test 992d6429b6bce16ac172f7431975044ceaeb0803
|
||||
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 76d3948568b2cdc0c13a671cadcae75009b183d6
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
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
|
||||
F test/select6.test 2b5e8500d8ec3dd4c8e0c99eb1431b3d11fcc24c
|
||||
F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test b4007b15396cb7ba2615cab31e1973b572e43210
|
||||
F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343
|
||||
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
|
||||
F test/shared3.test 9c880afc081d797da514ef64bccf36f3fce2f09c
|
||||
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
||||
F test/shared4.test d0fadacb50bb6981b2fb9dc6d1da30fa1edddf83
|
||||
F test/shared6.test 990d2584b5db28e6e1f24742c711b26e59757b67
|
||||
F test/shared7.test 8114027cb5e8c376e467115703d46e5ac4e77739
|
||||
@ -577,8 +598,8 @@ F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de
|
||||
F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/soak.test d9d0a5e5c0157115c9a17f526f12691fe146768d
|
||||
F test/softheap1.test 73ebd6e020d2954d965da2072baba5922fc8fb6a
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test c16709a16ad79fa43b32929b2e623d1d117ccf53
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
|
||||
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
|
||||
@ -589,37 +610,46 @@ F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/sqllimits1.test e90a0ed94452076f6a10209d378e06b5f75ef0a0
|
||||
F test/stmt.test ac97e59879fd3bd52ecd60ef4efb03ba16292829
|
||||
F test/stat.test 70fe540ffb285947aead5533dfd0c8c12f17f14e
|
||||
F test/stmt.test 7915bd3e8380b956c095f40f41a775a30716e649
|
||||
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/tempdb.test 1bf52da28a9c24e29717362a87722dff08feb72b
|
||||
F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
||||
F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||
F test/tester.tcl e1f581c7a2648a0aaa51135c4d2e7be68f4b9292
|
||||
F test/tester.tcl cab2b46972cd50c3939a0e30e0b37e73f558bc2d
|
||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||
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/thread2.test e08034b83fe9693ade77049732518e5b3d2d700d
|
||||
F test/thread_common.tcl 2aa6f2fdcd4d6e461169c3e5ca098eebf643b863
|
||||
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
|
||||
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
|
||||
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
|
||||
F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f
|
||||
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
|
||||
F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589
|
||||
F test/tkt-d11f09d36e.test fb44f7961aa6d4b632fb7b9768239832210b5fc7
|
||||
F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6
|
||||
F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87
|
||||
F test/tkt-f973c7ac31.test 1da0ed15ec2c7749fb5ce2828cd69d07153ad9f4
|
||||
F test/tkt-fc62af4523.test 72825d3febdedcd5593a27989fc05accdbfc2bb4
|
||||
F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00
|
||||
F test/tkt1443.test bacc311da5c96a227bf8c167e77a30c99f8e8368
|
||||
F test/tkt1444.test a9d72f9e942708bd82dde6c707da61c489e213e9
|
||||
@ -671,7 +701,6 @@ F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812
|
||||
F test/tkt3442.test 89d7b41a4ec4d9d9b40ab8575d648579fb13cb4f
|
||||
F test/tkt3457.test edbf54b05cbe5165f00192becbd621038f1615e4
|
||||
F test/tkt3461.test 228ea328a5a21e8663f80ee3d212a6ad92549a19
|
||||
F test/tkt3472.test 98c7e54b8fef2b1266a552a66c8e5d88a6908d1d
|
||||
F test/tkt3493.test 1686cbde85f8721fc1bdc0ee72f2ef2f63139218
|
||||
F test/tkt3508.test d75704db9501625c7f7deec119fcaf1696aefb7d
|
||||
F test/tkt3522.test 22ce2ebbcb04a6be56c0977d405c207967318fd6
|
||||
@ -706,7 +735,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 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
|
||||
F test/trigger1.test 2e18561f85e448bb633c9c9de792e9bbf7b2dd3e
|
||||
@ -715,12 +744,12 @@ F test/trigger3.test d2c60d8be271c355d61727411e753181e877230a
|
||||
F test/trigger4.test 8e90ee98cba940cd5f96493f82e55083806ab8a0
|
||||
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
|
||||
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
||||
F test/trigger7.test 72feaf8dbc52cea84de0c3e6ce7559ff19c479af
|
||||
F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4
|
||||
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,12 +757,12 @@ 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
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test e265401afefa994cdf2fe4b6f286b1e87c2f9b9d
|
||||
F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b
|
||||
F test/view.test 45f518205ecdb6dd23a86dd4a99bb4ae945e625d
|
||||
F test/vtab1.test 9bc4a349a1989bcd064eb3b8fac2f06aca64297a
|
||||
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
|
||||
@ -752,14 +781,29 @@ 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 1891e6f72dd437a1c2a48091aa9182ba17a8f780
|
||||
F test/wal2.test fa6dc4457b46988f46cf6c68ea51ebe341765f4a
|
||||
F test/wal3.test d2ae7e66f973bd6b58ce49e546b2c00f44fe0485
|
||||
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
|
||||
F test/wal_common.tcl 895d76138043b86bdccf36494054bdabcf65837b
|
||||
F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
|
||||
F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0
|
||||
F test/walcksum.test a37b36375c595e61bdb7e1ec49b5f0979b6fc7ce
|
||||
F test/walcrash.test e763841551d6b23677ccb419797c1589dcbdbaf5
|
||||
F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142
|
||||
F test/walfault.test 05c470688d742688e455dd56816bd6bcffa298f8
|
||||
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 5dc3008ef71988ecdd949ea16e5750e325b92b54
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
||||
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
|
||||
@ -770,39 +814,40 @@ F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/lemon.c 6958cb9935be265bf51dbc718ef325e3b77685b6
|
||||
F tool/lemon.c fe890e2d8d2db1e3f57e2a22503dbb0f6843e517
|
||||
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
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
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/shell1.test a738c71bc08ea9162baee9a14b3cf9994f181921
|
||||
F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3
|
||||
F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836
|
||||
F tool/showdb.c 01c20e8181941b714fe07f72c64a7560fee17ff9
|
||||
F tool/showjournal.c ec3b171be148656827c4949fbfb8ab4370822f87
|
||||
F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
|
||||
F tool/spaceanal.tcl b87db46ae29e3116411b1686e136b9b994d7de39
|
||||
F tool/spaceanal.tcl b91879d52bf77a1ff5382493284f429d32a63490
|
||||
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
|
||||
F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
||||
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 13ed106c8c279422a6159e28c6887d13a88b7b8b
|
||||
R 48f3b6e106f37a4303da6eef05383891
|
||||
U drh
|
||||
Z f7171db765620a4ccff85bc2ced22202
|
||||
Z 6f03f192e574b328cbf6ee712ebb1776
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFLrTT6oxKgR168RlERArP2AJ0UeA3bKxomgH1prR7M+4tHuMlN7wCfXBZE
|
||||
Jr7IGDFSJ/vsM6VpeiKkkf4=
|
||||
=diSA
|
||||
iD8DBQFMRx1eoxKgR168RlERAkrAAJ9jYeUOTv2JXqP7/ZLTAQf2A6QoNACeLuA0
|
||||
lTLlFWVnujV93G1zfacFBTo=
|
||||
=MCKn
|
||||
-----END PGP SIGNATURE-----
|
||||
|
@ -1 +1 @@
|
||||
b078b588d617e07886ad156e9f54ade6d823568e
|
||||
b36b105eab6fd3195f4bfba6cb5cda0f063b7460
|
||||
|
27
publish.sh
27
publish.sh
@ -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'
|
||||
|
29
src/alter.c
29
src/alter.c
@ -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
|
||||
|
@ -36,7 +36,7 @@ static void openStatTable(
|
||||
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
|
||||
const char *zWhere /* Delete entries associated with this table */
|
||||
){
|
||||
static struct {
|
||||
static const struct {
|
||||
const char *zName;
|
||||
const char *zCols;
|
||||
} aTable[] = {
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,6 @@ static void attachFunc(
|
||||
}
|
||||
pPager = sqlite3BtreePager(aNew->pBt);
|
||||
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
|
||||
sqlite3PagerJournalMode(pPager, db->dfltJournalMode);
|
||||
sqlite3BtreeSecureDelete(aNew->pBt,
|
||||
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
|
||||
}
|
||||
@ -288,7 +287,7 @@ detach_error:
|
||||
static void codeAttach(
|
||||
Parse *pParse, /* The parser context */
|
||||
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
|
||||
FuncDef *pFunc, /* FuncDef wrapper for detachFunc() or attachFunc() */
|
||||
FuncDef const *pFunc,/* FuncDef wrapper for detachFunc() or attachFunc() */
|
||||
Expr *pAuthArg, /* Expression to pass to authorization callback */
|
||||
Expr *pFilename, /* Name of database file */
|
||||
Expr *pDbname, /* Name of the database to use internally */
|
||||
@ -358,7 +357,7 @@ attach_end:
|
||||
** DETACH pDbname
|
||||
*/
|
||||
void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
||||
static FuncDef detach_func = {
|
||||
static const FuncDef detach_func = {
|
||||
1, /* nArg */
|
||||
SQLITE_UTF8, /* iPrefEnc */
|
||||
0, /* flags */
|
||||
@ -379,7 +378,7 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
||||
** ATTACH p AS pDbname KEY pKey
|
||||
*/
|
||||
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
|
||||
static FuncDef attach_func = {
|
||||
static const FuncDef attach_func = {
|
||||
3, /* nArg */
|
||||
SQLITE_UTF8, /* iPrefEnc */
|
||||
0, /* flags */
|
||||
|
50
src/backup.c
50
src/backup.c
@ -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,21 @@ 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 = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
|
||||
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 +375,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 +393,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 +416,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);
|
||||
}
|
||||
@ -458,6 +469,9 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
assert( rc2==SQLITE_OK );
|
||||
}
|
||||
|
||||
if( rc==SQLITE_IOERR_NOMEM ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
p->rc = rc;
|
||||
}
|
||||
if( p->pDestDb ){
|
||||
|
235
src/btree.c
235
src/btree.c
@ -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,25 +1583,22 @@ static int getAndInitPage(
|
||||
MemPage **ppPage /* Write the page pointer here */
|
||||
){
|
||||
int rc;
|
||||
TESTONLY( Pgno iLastPg = pagerPagecount(pBt); )
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
|
||||
rc = btreeGetPage(pBt, pgno, ppPage, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = btreeInitPage(*ppPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
releasePage(*ppPage);
|
||||
if( pgno>btreePagecount(pBt) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = btreeGetPage(pBt, pgno, ppPage, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = btreeInitPage(*ppPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
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 );
|
||||
|
||||
assert( pgno!=0 || rc==SQLITE_CORRUPT );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2240,9 +2234,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 +2250,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 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
|
||||
nPage = nPageFile;
|
||||
}
|
||||
if( nPage>0 ){
|
||||
int pageSize;
|
||||
int usableSize;
|
||||
u8 *page1 = pPage1->aData;
|
||||
@ -2265,12 +2265,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 +2333,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 +2367,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 +2405,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 +2434,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 +2525,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
||||
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
|
||||
if( SQLITE_OK!=rc ) goto trans_begun;
|
||||
|
||||
pBt->initiallyEmpty = (u8)(pBt->nPage==0);
|
||||
do {
|
||||
/* Call lockBtree() until either pBt->pPage1 is populated or
|
||||
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
||||
@ -2514,7 +2550,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
||||
if( rc!=SQLITE_OK ){
|
||||
unlockBtreeIfUnused(pBt);
|
||||
}
|
||||
}while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
|
||||
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
|
||||
btreeInvokeBusyHandler(pBt) );
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -2769,12 +2805,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 +2886,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 +2899,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
||||
iLastPg--;
|
||||
}
|
||||
sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
|
||||
pBt->nPage = iLastPg;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -2885,7 +2922,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 +2957,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 +2982,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 +3237,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 +3279,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 +3311,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 +3382,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 +3653,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;
|
||||
@ -4200,7 +4248,6 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
|
||||
if( pCur->eState==CURSOR_INVALID ){
|
||||
assert( pCur->apPage[pCur->iPage]->nCell==0 );
|
||||
*pRes = 1;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
assert( pCur->apPage[pCur->iPage]->nCell>0 );
|
||||
*pRes = 0;
|
||||
@ -4637,7 +4684,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 +4880,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 +5098,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 +6930,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 +6977,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 +7728,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 +7996,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 = (u8)(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 */
|
||||
|
@ -2614,6 +2614,7 @@ Index *sqlite3CreateIndex(
|
||||
if( j>=pTab->nCol ){
|
||||
sqlite3ErrorMsg(pParse, "table %s has no column named %s",
|
||||
pTab->zName, zColName);
|
||||
pParse->checkSchema = 1;
|
||||
goto exit_create_index;
|
||||
}
|
||||
pIndex->aiColumn[i] = j;
|
||||
@ -3382,7 +3383,7 @@ void sqlite3Savepoint(Parse *pParse, int op, Token *pName){
|
||||
if( zName ){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
static const char *az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
|
||||
static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
|
||||
assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 );
|
||||
#endif
|
||||
if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){
|
||||
@ -3422,7 +3423,6 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
db->mallocFailed = 1;
|
||||
return 1;
|
||||
}
|
||||
sqlite3PagerJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -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);
|
||||
|
17
src/ctime.c
17
src/ctime.c
@ -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
|
||||
@ -192,9 +195,11 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_CHECK
|
||||
"OMIT_CHECK",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
"OMIT_COMPILEOPTION_DIAGS",
|
||||
#endif
|
||||
/* // redundant
|
||||
** #ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
** "OMIT_COMPILEOPTION_DIAGS",
|
||||
** #endif
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_COMPLETE
|
||||
"OMIT_COMPLETE",
|
||||
#endif
|
||||
@ -228,9 +233,6 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_GET_TABLE
|
||||
"OMIT_GET_TABLE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_GLOBALRECOVER
|
||||
"OMIT_GLOBALRECOVER",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
"OMIT_INCRBLOB",
|
||||
#endif
|
||||
@ -309,6 +311,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
"OMIT_VIRTUALTABLE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
"OMIT_WAL",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_WSD
|
||||
"OMIT_WSD",
|
||||
#endif
|
||||
|
17
src/date.c
17
src/date.c
@ -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;
|
||||
|
@ -508,9 +508,7 @@ void sqlite3GenerateRowDelete(
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld);
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
if( mask==0xffffffff || mask&(1<<iCol) ){
|
||||
int iTarget = iOld + iCol + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, iCol, iTarget);
|
||||
sqlite3ColumnDefault(v, pTab, iCol, iTarget);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld+iCol+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
109
src/expr.c
109
src/expr.c
@ -1635,7 +1635,7 @@ int sqlite3CodeSubselect(
|
||||
keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
|
||||
pEList->a[0].pExpr);
|
||||
}
|
||||
}else if( pExpr->x.pList!=0 ){
|
||||
}else if( ALWAYS(pExpr->x.pList!=0) ){
|
||||
/* Case 2: expr IN (exprlist)
|
||||
**
|
||||
** For each expression, build an index key from the evaluation and
|
||||
@ -1705,7 +1705,6 @@ int sqlite3CodeSubselect(
|
||||
** an integer 0 (not exists) or 1 (exists) into a memory cell
|
||||
** and record that memory cell in iColumn.
|
||||
*/
|
||||
static const Token one = { "1", 1 }; /* Token for literal value 1 */
|
||||
Select *pSel; /* SELECT statement to encode */
|
||||
SelectDest dest; /* How to deal with SELECt result */
|
||||
|
||||
@ -1726,7 +1725,8 @@ int sqlite3CodeSubselect(
|
||||
VdbeComment((v, "Init EXISTS result"));
|
||||
}
|
||||
sqlite3ExprDelete(pParse->db, pSel->pLimit);
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one);
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
|
||||
&sqlite3IntTokens[1]);
|
||||
if( sqlite3Select(pParse, pSel, &dest) ){
|
||||
return 0;
|
||||
}
|
||||
@ -1794,8 +1794,20 @@ static void sqlite3ExprCodeIN(
|
||||
sqlite3ExprCachePush(pParse);
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3ExprCode(pParse, pExpr->pLeft, r1);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull);
|
||||
|
||||
/* If the LHS is NULL, then the result is either false or NULL depending
|
||||
** on whether the RHS is empty or not, respectively.
|
||||
*/
|
||||
if( destIfNull==destIfFalse ){
|
||||
/* Shortcut for the common case where the false and NULL outcomes are
|
||||
** the same. */
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull);
|
||||
}else{
|
||||
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}
|
||||
|
||||
if( eType==IN_INDEX_ROWID ){
|
||||
/* In this case, the RHS is the ROWID of table b-tree
|
||||
@ -2082,6 +2094,27 @@ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to extract the value of the iCol-th column of a table.
|
||||
*/
|
||||
void sqlite3ExprCodeGetColumnOfTable(
|
||||
Vdbe *v, /* The VDBE under construction */
|
||||
Table *pTab, /* The table containing the value */
|
||||
int iTabCur, /* The cursor for this table */
|
||||
int iCol, /* Index of the column to extract */
|
||||
int regOut /* Extract the valud into this register */
|
||||
){
|
||||
if( iCol<0 || iCol==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
|
||||
}else{
|
||||
int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
|
||||
sqlite3VdbeAddOp3(v, op, iTabCur, iCol, regOut);
|
||||
}
|
||||
if( iCol>=0 ){
|
||||
sqlite3ColumnDefault(v, pTab, iCol, regOut);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will extract the iColumn-th column from
|
||||
** table pTab and store the column value in a register. An effort
|
||||
@ -2110,13 +2143,7 @@ int sqlite3ExprCodeGetColumn(
|
||||
}
|
||||
}
|
||||
assert( v!=0 );
|
||||
if( iColumn<0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iTable, iReg);
|
||||
}else if( ALWAYS(pTab!=0) ){
|
||||
int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
|
||||
sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg);
|
||||
sqlite3ColumnDefault(v, pTab, iColumn, iReg);
|
||||
}
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
|
||||
sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
|
||||
return iReg;
|
||||
}
|
||||
@ -2353,27 +2380,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 +3452,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 +3464,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 +3481,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
|
||||
|
22
src/func.c
22
src/func.c
@ -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
|
||||
}
|
||||
|
11
src/global.c
11
src/global.c
@ -176,6 +176,15 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
*/
|
||||
SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
|
||||
|
||||
/*
|
||||
** Constant tokens for values 0 and 1.
|
||||
*/
|
||||
const Token sqlite3IntTokens[] = {
|
||||
{ "0", 1 },
|
||||
{ "1", 1 }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** The value of the "pending" byte must be 0x40000000 (1 byte past the
|
||||
** 1-gibabyte boundary) in a compatible database. SQLite never uses
|
||||
@ -194,7 +203,9 @@ SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
|
||||
** Changing the pending byte during operating results in undefined
|
||||
** and dileterious behavior.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
int sqlite3PendingByte = 0x40000000;
|
||||
#endif
|
||||
|
||||
#include "opcodes.h"
|
||||
/*
|
||||
|
@ -727,7 +727,7 @@ void sqlite3Insert(
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
|
||||
pTabList, 0, pColumn->a[i].zName);
|
||||
pParse->nErr++;
|
||||
pParse->checkSchema = 1;
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
@ -182,7 +182,11 @@ static struct sqlite3_io_methods JournalFileMethods = {
|
||||
0, /* xCheckReservedLock */
|
||||
0, /* xFileControl */
|
||||
0, /* xSectorSize */
|
||||
0 /* xDeviceCharacteristics */
|
||||
0, /* xDeviceCharacteristics */
|
||||
0, /* xShmMap */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmBarrier */
|
||||
0 /* xShmUnmap */
|
||||
};
|
||||
|
||||
/*
|
||||
|
177
src/main.c
177
src/main.c
@ -776,7 +776,7 @@ const char *sqlite3ErrStr(int rc){
|
||||
/* SQLITE_NOTFOUND */ 0,
|
||||
/* SQLITE_FULL */ "database or disk is full",
|
||||
/* SQLITE_CANTOPEN */ "unable to open database file",
|
||||
/* SQLITE_PROTOCOL */ 0,
|
||||
/* SQLITE_PROTOCOL */ "locking protocol",
|
||||
/* SQLITE_EMPTY */ "table contains no data",
|
||||
/* SQLITE_SCHEMA */ "database schema has changed",
|
||||
/* SQLITE_TOOBIG */ "string or blob too big",
|
||||
@ -1186,6 +1186,145 @@ 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) ){
|
||||
sqlite3BeginBenignMalloc();
|
||||
sqlite3_wal_checkpoint(db, zDb);
|
||||
sqlite3EndBenignMalloc();
|
||||
}
|
||||
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 +1747,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 +1885,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 );
|
||||
@ -1920,7 +2061,6 @@ int sqlite3_collation_needed16(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
/*
|
||||
** This function is now an anachronism. It used to be used to recover from a
|
||||
@ -1930,7 +2070,6 @@ int sqlite3_global_recover(void){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Test to see whether or not the database connection is in autocommit
|
||||
@ -1958,17 +2097,22 @@ int sqlite3_get_autocommit(sqlite3 *db){
|
||||
int sqlite3CorruptError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_CORRUPT,
|
||||
"database corruption found by source line %d", lineno);
|
||||
"database corruption at line %d of [%.10s]",
|
||||
lineno, 20+sqlite3_sourceid());
|
||||
return SQLITE_CORRUPT;
|
||||
}
|
||||
int sqlite3MisuseError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_MISUSE, "misuse detected by source line %d", lineno);
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
"misuse at line %d of [%.10s]",
|
||||
lineno, 20+sqlite3_sourceid());
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
int sqlite3CantopenError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_CANTOPEN, "cannot open file at source line %d", lineno);
|
||||
sqlite3_log(SQLITE_CANTOPEN,
|
||||
"cannot open file at line %d of [%.10s]",
|
||||
lineno, 20+sqlite3_sourceid());
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
|
||||
@ -2240,9 +2384,13 @@ int sqlite3_test_control(int op, ...){
|
||||
** dileterious behavior.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_PENDING_BYTE: {
|
||||
unsigned int newVal = va_arg(ap, unsigned int);
|
||||
rc = sqlite3PendingByte;
|
||||
if( newVal ) sqlite3PendingByte = newVal;
|
||||
rc = PENDING_BYTE;
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
{
|
||||
unsigned int newVal = va_arg(ap, unsigned int);
|
||||
if( newVal ) sqlite3PendingByte = newVal;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2346,6 +2494,15 @@ int sqlite3_test_control(int op, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_PGHDRSZ)
|
||||
**
|
||||
** Return the size of a pcache header in bytes.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_PGHDRSZ: {
|
||||
rc = sizeof(PgHdr);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
|
40
src/malloc.c
40
src/malloc.c
@ -315,11 +315,11 @@ void *sqlite3ScratchMalloc(int n){
|
||||
assert( n>0 );
|
||||
|
||||
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
|
||||
/* Verify that no more than one scratch allocation per thread
|
||||
/* Verify that no more than two scratch allocation per thread
|
||||
** is outstanding at one time. (This is only checked in the
|
||||
** single-threaded case since checking in the multi-threaded case
|
||||
** would be much more complicated.) */
|
||||
assert( scratchAllocOut==0 );
|
||||
assert( scratchAllocOut<=1 );
|
||||
#endif
|
||||
|
||||
if( sqlite3GlobalConfig.szScratch<n ){
|
||||
@ -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
|
||||
@ -363,19 +364,11 @@ scratch_overflow:
|
||||
}
|
||||
void sqlite3ScratchFree(void *p){
|
||||
if( p ){
|
||||
|
||||
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
|
||||
/* Verify that no more than one scratch allocation per thread
|
||||
** is outstanding at one time. (This is only checked in the
|
||||
** single-threaded case since checking in the multi-threaded case
|
||||
** would be much more complicated.) */
|
||||
assert( scratchAllocOut==1 );
|
||||
scratchAllocOut = 0;
|
||||
#endif
|
||||
|
||||
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);
|
||||
@ -396,6 +389,16 @@ void sqlite3ScratchFree(void *p){
|
||||
mem0.aScratchFree[mem0.nScratchFree++] = i;
|
||||
sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
|
||||
sqlite3_mutex_leave(mem0.mutex);
|
||||
|
||||
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
|
||||
/* Verify that no more than two scratch allocation per thread
|
||||
** is outstanding at one time. (This is only checked in the
|
||||
** single-threaded case since checking in the multi-threaded case
|
||||
** would be much more complicated.) */
|
||||
assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
|
||||
scratchAllocOut = 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
45
src/mem2.c
45
src/mem2.c
@ -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
|
||||
|
@ -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.
|
||||
@ -214,7 +213,7 @@ static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
|
||||
/*
|
||||
** Table of methods for MemJournal sqlite3_file object.
|
||||
*/
|
||||
static struct sqlite3_io_methods MemJournalMethods = {
|
||||
static const struct sqlite3_io_methods MemJournalMethods = {
|
||||
1, /* iVersion */
|
||||
memjrnlClose, /* xClose */
|
||||
memjrnlRead, /* xRead */
|
||||
@ -227,7 +226,11 @@ static struct sqlite3_io_methods MemJournalMethods = {
|
||||
0, /* xCheckReservedLock */
|
||||
0, /* xFileControl */
|
||||
0, /* xSectorSize */
|
||||
0 /* xDeviceCharacteristics */
|
||||
0, /* xDeviceCharacteristics */
|
||||
0, /* xShmMap */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmBarrier */
|
||||
0 /* xShmUnlock */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -237,7 +240,7 @@ void sqlite3MemJournalOpen(sqlite3_file *pJfd){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
assert( EIGHT_BYTE_ALIGNMENT(p) );
|
||||
memset(p, 0, sqlite3MemJournalSize());
|
||||
p->pMethod = &MemJournalMethods;
|
||||
p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
|
||||
}
|
||||
|
||||
/*
|
||||
|
31
src/mutex.c
31
src/mutex.c
@ -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 const *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;
|
||||
|
@ -27,25 +27,30 @@
|
||||
*/
|
||||
#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; }
|
||||
static void noopMutexFree(sqlite3_mutex *p){ return; }
|
||||
static void noopMutexEnter(sqlite3_mutex *p){ return; }
|
||||
static int noopMutexTry(sqlite3_mutex *p){ return SQLITE_OK; }
|
||||
static void noopMutexLeave(sqlite3_mutex *p){ return; }
|
||||
static sqlite3_mutex *noopMutexAlloc(int id){
|
||||
UNUSED_PARAMETER(id);
|
||||
return (sqlite3_mutex*)8;
|
||||
}
|
||||
static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
|
||||
static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
|
||||
static int noopMutexTry(sqlite3_mutex *p){
|
||||
UNUSED_PARAMETER(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
|
||||
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
static sqlite3_mutex_methods sMutex = {
|
||||
sqlite3_mutex_methods const *sqlite3NoopMutex(void){
|
||||
static const sqlite3_mutex_methods sMutex = {
|
||||
noopMutexInit,
|
||||
noopMutexEnd,
|
||||
noopMutexAlloc,
|
||||
@ -54,15 +59,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 +77,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 +107,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 +127,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 +151,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,14 +169,15 @@ 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){
|
||||
static sqlite3_mutex_methods sMutex = {
|
||||
sqlite3_mutex_methods const *sqlite3NoopMutex(void){
|
||||
static const sqlite3_mutex_methods sMutex = {
|
||||
debugMutexInit,
|
||||
debugMutexEnd,
|
||||
debugMutexAlloc,
|
||||
@ -181,4 +192,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 const *sqlite3DefaultMutex(void){
|
||||
return sqlite3NoopMutex();
|
||||
}
|
||||
#endif /* SQLITE_MUTEX_NOOP */
|
||||
#endif /* SQLITE_MUTEX_OMIT */
|
||||
|
@ -251,8 +251,8 @@ static void os2MutexLeave(sqlite3_mutex *p){
|
||||
DosReleaseMutexSem(p->mutex);
|
||||
}
|
||||
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
static sqlite3_mutex_methods sMutex = {
|
||||
sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
|
||||
static const sqlite3_mutex_methods sMutex = {
|
||||
os2MutexInit,
|
||||
os2MutexEnd,
|
||||
os2MutexAlloc,
|
||||
|
@ -24,23 +24,33 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
|
||||
** are necessary under two condidtions: (1) Debug builds and (2) using
|
||||
** home-grown mutexes. Encapsulate these conditions into a single #define.
|
||||
*/
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
|
||||
# define SQLITE_MUTEX_NREF 1
|
||||
#else
|
||||
# define SQLITE_MUTEX_NREF 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Each recursive mutex is an instance of the following structure.
|
||||
*/
|
||||
struct sqlite3_mutex {
|
||||
pthread_mutex_t mutex; /* Mutex controlling the lock */
|
||||
#if SQLITE_MUTEX_NREF
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of entrances */
|
||||
pthread_t owner; /* Thread that is within this mutex */
|
||||
#ifdef SQLITE_DEBUG
|
||||
volatile int nRef; /* Number of entrances */
|
||||
volatile pthread_t owner; /* Thread that is within this mutex */
|
||||
int trace; /* True to trace changes */
|
||||
#endif
|
||||
};
|
||||
#ifdef SQLITE_DEBUG
|
||||
#if SQLITE_MUTEX_NREF
|
||||
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
|
||||
#else
|
||||
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0 }
|
||||
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -142,14 +152,18 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
pthread_mutex_init(&p->mutex, &recursiveAttr);
|
||||
pthread_mutexattr_destroy(&recursiveAttr);
|
||||
#endif
|
||||
#if SQLITE_MUTEX_NREF
|
||||
p->id = iType;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_MUTEX_FAST: {
|
||||
p = sqlite3MallocZero( sizeof(*p) );
|
||||
if( p ){
|
||||
#if SQLITE_MUTEX_NREF
|
||||
p->id = iType;
|
||||
#endif
|
||||
pthread_mutex_init(&p->mutex, 0);
|
||||
}
|
||||
break;
|
||||
@ -158,7 +172,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
assert( iType-2 >= 0 );
|
||||
assert( iType-2 < ArraySize(staticMutexes) );
|
||||
p = &staticMutexes[iType-2];
|
||||
#if SQLITE_MUTEX_NREF
|
||||
p->id = iType;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -218,9 +234,11 @@ static void pthreadMutexEnter(sqlite3_mutex *p){
|
||||
/* Use the built-in recursive mutexes if they are available.
|
||||
*/
|
||||
pthread_mutex_lock(&p->mutex);
|
||||
#if SQLITE_MUTEX_NREF
|
||||
p->owner = pthread_self();
|
||||
p->nRef++;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
@ -261,8 +279,10 @@ static int pthreadMutexTry(sqlite3_mutex *p){
|
||||
/* Use the built-in recursive mutexes if they are available.
|
||||
*/
|
||||
if( pthread_mutex_trylock(&p->mutex)==0 ){
|
||||
#if SQLITE_MUTEX_NREF
|
||||
p->owner = pthread_self();
|
||||
p->nRef++;
|
||||
#endif
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = SQLITE_BUSY;
|
||||
@ -285,7 +305,9 @@ static int pthreadMutexTry(sqlite3_mutex *p){
|
||||
*/
|
||||
static void pthreadMutexLeave(sqlite3_mutex *p){
|
||||
assert( pthreadMutexHeld(p) );
|
||||
#if SQLITE_MUTEX_NREF
|
||||
p->nRef--;
|
||||
#endif
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
|
||||
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
|
||||
@ -303,8 +325,8 @@ static void pthreadMutexLeave(sqlite3_mutex *p){
|
||||
#endif
|
||||
}
|
||||
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
static sqlite3_mutex_methods sMutex = {
|
||||
sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
|
||||
static const sqlite3_mutex_methods sMutex = {
|
||||
pthreadMutexInit,
|
||||
pthreadMutexEnd,
|
||||
pthreadMutexAlloc,
|
||||
|
@ -25,9 +25,9 @@
|
||||
struct sqlite3_mutex {
|
||||
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of enterances */
|
||||
DWORD owner; /* Thread holding this mutex */
|
||||
#ifdef SQLITE_DEBUG
|
||||
volatile int nRef; /* Number of enterances */
|
||||
volatile DWORD owner; /* Thread holding this mutex */
|
||||
int trace; /* True to trace changes */
|
||||
#endif
|
||||
};
|
||||
@ -35,7 +35,7 @@ struct sqlite3_mutex {
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
|
||||
#else
|
||||
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0 }
|
||||
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -191,7 +191,9 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
p = sqlite3MallocZero( sizeof(*p) );
|
||||
if( p ){
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->id = iType;
|
||||
#endif
|
||||
InitializeCriticalSection(&p->mutex);
|
||||
}
|
||||
break;
|
||||
@ -201,7 +203,9 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
assert( iType-2 >= 0 );
|
||||
assert( iType-2 < ArraySize(winMutex_staticMutexes) );
|
||||
p = &winMutex_staticMutexes[iType-2];
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->id = iType;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -234,12 +238,14 @@ static void winMutexFree(sqlite3_mutex *p){
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
static void winMutexEnter(sqlite3_mutex *p){
|
||||
#ifdef SQLITE_DEBUG
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
|
||||
#endif
|
||||
EnterCriticalSection(&p->mutex);
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
@ -288,11 +294,11 @@ static int winMutexTry(sqlite3_mutex *p){
|
||||
static void winMutexLeave(sqlite3_mutex *p){
|
||||
#ifndef NDEBUG
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
assert( p->nRef>0 );
|
||||
assert( p->owner==tid );
|
||||
p->nRef--;
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
#endif
|
||||
LeaveCriticalSection(&p->mutex);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
@ -301,8 +307,8 @@ static void winMutexLeave(sqlite3_mutex *p){
|
||||
#endif
|
||||
}
|
||||
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
|
||||
static sqlite3_mutex_methods sMutex = {
|
||||
sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
|
||||
static const sqlite3_mutex_methods sMutex = {
|
||||
winMutexInit,
|
||||
winMutexEnd,
|
||||
winMutexAlloc,
|
||||
|
@ -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;
|
||||
|
40
src/os.c
40
src/os.c
@ -34,8 +34,10 @@
|
||||
** sqlite3OsLock()
|
||||
**
|
||||
*/
|
||||
#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0)
|
||||
#define DO_OS_MALLOC_TEST(x) if (!x || !sqlite3IsMemJournal(x)) { \
|
||||
#if defined(SQLITE_TEST)
|
||||
int sqlite3_memdebug_vfs_oom_test = 1;
|
||||
#define DO_OS_MALLOC_TEST(x) \
|
||||
if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
|
||||
void *pTstAlloc = sqlite3Malloc(10); \
|
||||
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
|
||||
sqlite3_free(pTstAlloc); \
|
||||
@ -98,6 +100,24 @@ int sqlite3OsSectorSize(sqlite3_file *id){
|
||||
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
|
||||
return id->pMethods->xDeviceCharacteristics(id);
|
||||
}
|
||||
int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
|
||||
return id->pMethods->xShmLock(id, offset, n, flags);
|
||||
}
|
||||
void sqlite3OsShmBarrier(sqlite3_file *id){
|
||||
id->pMethods->xShmBarrier(id);
|
||||
}
|
||||
int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){
|
||||
return id->pMethods->xShmUnmap(id, deleteFlag);
|
||||
}
|
||||
int sqlite3OsShmMap(
|
||||
sqlite3_file *id, /* Database file handle */
|
||||
int iPage,
|
||||
int pgsz,
|
||||
int bExtend, /* True to extend file if necessary */
|
||||
void volatile **pp /* OUT: Pointer to mapping */
|
||||
){
|
||||
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
|
||||
}
|
||||
|
||||
/*
|
||||
** The next group of routines are convenience wrappers around the
|
||||
@ -112,11 +132,11 @@ int sqlite3OsOpen(
|
||||
){
|
||||
int rc;
|
||||
DO_OS_MALLOC_TEST(0);
|
||||
/* 0x7f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
|
||||
/* 0x87f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
|
||||
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
|
||||
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
|
||||
** reaching the VFS. */
|
||||
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f3f, pFlagsOut);
|
||||
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f3f, pFlagsOut);
|
||||
assert( rc==SQLITE_OK || pFile->pMethods==0 );
|
||||
return rc;
|
||||
}
|
||||
@ -161,8 +181,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(
|
||||
|
12
src/os.h
12
src/os.h
@ -217,7 +217,11 @@
|
||||
** 1GB boundary.
|
||||
**
|
||||
*/
|
||||
#define PENDING_BYTE sqlite3PendingByte
|
||||
#ifdef SQLITE_OMIT_WSD
|
||||
# define PENDING_BYTE (0x40000000)
|
||||
#else
|
||||
# define PENDING_BYTE sqlite3PendingByte
|
||||
#endif
|
||||
#define RESERVED_BYTE (PENDING_BYTE+1)
|
||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||
#define SHARED_SIZE 510
|
||||
@ -243,6 +247,10 @@ int sqlite3OsFileControl(sqlite3_file*,int,void*);
|
||||
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
|
||||
int sqlite3OsSectorSize(sqlite3_file *id);
|
||||
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
|
||||
int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
|
||||
int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
|
||||
void sqlite3OsShmBarrier(sqlite3_file *id);
|
||||
int sqlite3OsShmUnmap(sqlite3_file *id, int);
|
||||
|
||||
/*
|
||||
** Functions for accessing sqlite3_vfs methods
|
||||
@ -259,7 +267,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
|
||||
|
@ -31,23 +31,9 @@
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3OSTrace = 0;
|
||||
#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
|
||||
#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
|
||||
#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
|
||||
#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
|
||||
#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
|
||||
#define OSTRACE6(X,Y,Z,A,B,C) \
|
||||
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)
|
||||
#define OSTRACE3(X,Y,Z)
|
||||
#define OSTRACE4(X,Y,Z,A)
|
||||
#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
|
||||
|
||||
/*
|
||||
|
108
src/os_os2.c
108
src/os_os2.c
@ -81,7 +81,7 @@ static int os2Close( sqlite3_file *id ){
|
||||
APIRET rc = NO_ERROR;
|
||||
os2File *pFile;
|
||||
if( id && (pFile = (os2File*)id) != 0 ){
|
||||
OSTRACE2( "CLOSE %d\n", pFile->h );
|
||||
OSTRACE(( "CLOSE %d\n", pFile->h ));
|
||||
rc = DosClose( pFile->h );
|
||||
pFile->locktype = NO_LOCK;
|
||||
if( pFile->pathToDel != NULL ){
|
||||
@ -112,7 +112,7 @@ static int os2Read(
|
||||
os2File *pFile = (os2File*)id;
|
||||
assert( id!=0 );
|
||||
SimulateIOError( return SQLITE_IOERR_READ );
|
||||
OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype );
|
||||
OSTRACE(( "READ %d lock=%d\n", pFile->h, pFile->locktype ));
|
||||
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
@ -145,7 +145,7 @@ static int os2Write(
|
||||
assert( id!=0 );
|
||||
SimulateIOError( return SQLITE_IOERR_WRITE );
|
||||
SimulateDiskfullError( return SQLITE_FULL );
|
||||
OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype );
|
||||
OSTRACE(( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ));
|
||||
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
@ -167,7 +167,7 @@ static int os2Write(
|
||||
static int os2Truncate( sqlite3_file *id, i64 nByte ){
|
||||
APIRET rc = NO_ERROR;
|
||||
os2File *pFile = (os2File*)id;
|
||||
OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte );
|
||||
OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
|
||||
SimulateIOError( return SQLITE_IOERR_TRUNCATE );
|
||||
rc = DosSetFileSize( pFile->h, nByte );
|
||||
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
|
||||
@ -187,7 +187,7 @@ int sqlite3_fullsync_count = 0;
|
||||
*/
|
||||
static int os2Sync( sqlite3_file *id, int flags ){
|
||||
os2File *pFile = (os2File*)id;
|
||||
OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype );
|
||||
OSTRACE(( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ));
|
||||
#ifdef SQLITE_TEST
|
||||
if( flags & SQLITE_SYNC_FULL){
|
||||
sqlite3_fullsync_count++;
|
||||
@ -237,7 +237,7 @@ static int getReadLock( os2File *pFile ){
|
||||
UnlockArea.lOffset = 0L;
|
||||
UnlockArea.lRange = 0L;
|
||||
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
|
||||
OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "GETREADLOCK %d res=%d\n", pFile->h, res ));
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ static int unlockReadLock( os2File *id ){
|
||||
UnlockArea.lOffset = SHARED_FIRST;
|
||||
UnlockArea.lRange = SHARED_SIZE;
|
||||
res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
|
||||
OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res );
|
||||
OSTRACE(( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ));
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -296,14 +296,14 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
memset(&LockArea, 0, sizeof(LockArea));
|
||||
memset(&UnlockArea, 0, sizeof(UnlockArea));
|
||||
assert( pFile!=0 );
|
||||
OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
|
||||
OSTRACE(( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ));
|
||||
|
||||
/* If there is already a lock of this type or more restrictive on the
|
||||
** os2File, do nothing. Don't use the end_lock: exit path, as
|
||||
** sqlite3_mutex_enter() hasn't been called yet.
|
||||
*/
|
||||
if( pFile->locktype>=locktype ){
|
||||
OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype );
|
||||
OSTRACE(( "LOCK %d %d ok (already held)\n", pFile->h, locktype ));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -330,7 +330,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
|
||||
if( res == NO_ERROR ){
|
||||
gotPendingLock = 1;
|
||||
OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ));
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,7 +342,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
if( res == NO_ERROR ){
|
||||
newLocktype = SHARED_LOCK;
|
||||
}
|
||||
OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ));
|
||||
}
|
||||
|
||||
/* Acquire a RESERVED lock
|
||||
@ -357,7 +357,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
if( res == NO_ERROR ){
|
||||
newLocktype = RESERVED_LOCK;
|
||||
}
|
||||
OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ));
|
||||
}
|
||||
|
||||
/* Acquire a PENDING lock
|
||||
@ -365,7 +365,8 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
|
||||
newLocktype = PENDING_LOCK;
|
||||
gotPendingLock = 0;
|
||||
OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h );
|
||||
OSTRACE(( "LOCK %d acquire pending lock. pending lock boolean unset.\n",
|
||||
pFile->h ));
|
||||
}
|
||||
|
||||
/* Acquire an EXCLUSIVE lock
|
||||
@ -373,7 +374,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
|
||||
assert( pFile->locktype>=SHARED_LOCK );
|
||||
res = unlockReadLock(pFile);
|
||||
OSTRACE2( "unreadlock = %d\n", res );
|
||||
OSTRACE(( "unreadlock = %d\n", res ));
|
||||
LockArea.lOffset = SHARED_FIRST;
|
||||
LockArea.lRange = SHARED_SIZE;
|
||||
UnlockArea.lOffset = 0L;
|
||||
@ -382,10 +383,10 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
if( res == NO_ERROR ){
|
||||
newLocktype = EXCLUSIVE_LOCK;
|
||||
}else{
|
||||
OSTRACE2( "OS/2 error-code = %d\n", res );
|
||||
OSTRACE(( "OS/2 error-code = %d\n", res ));
|
||||
getReadLock(pFile);
|
||||
}
|
||||
OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ));
|
||||
}
|
||||
|
||||
/* If we are holding a PENDING lock that ought to be released, then
|
||||
@ -398,7 +399,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
UnlockArea.lOffset = PENDING_BYTE;
|
||||
UnlockArea.lRange = 1L;
|
||||
r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
|
||||
OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r );
|
||||
OSTRACE(( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ));
|
||||
}
|
||||
|
||||
/* Update the state of the lock has held in the file descriptor then
|
||||
@ -407,12 +408,12 @@ static int os2Lock( sqlite3_file *id, int locktype ){
|
||||
if( res == NO_ERROR ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
|
||||
locktype, newLocktype );
|
||||
OSTRACE(( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
|
||||
locktype, newLocktype ));
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
pFile->locktype = newLocktype;
|
||||
OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype );
|
||||
OSTRACE(( "LOCK %d now %d\n", pFile->h, pFile->locktype ));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -427,7 +428,7 @@ static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
|
||||
assert( pFile!=0 );
|
||||
if( pFile->locktype>=RESERVED_LOCK ){
|
||||
r = 1;
|
||||
OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r );
|
||||
OSTRACE(( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ));
|
||||
}else{
|
||||
FILELOCK LockArea,
|
||||
UnlockArea;
|
||||
@ -439,7 +440,7 @@ static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
|
||||
UnlockArea.lOffset = 0L;
|
||||
UnlockArea.lRange = 0L;
|
||||
rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
|
||||
OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc );
|
||||
OSTRACE(( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ));
|
||||
if( rc == NO_ERROR ){
|
||||
APIRET rcu = NO_ERROR; /* return code for unlocking */
|
||||
LockArea.lOffset = 0L;
|
||||
@ -447,10 +448,10 @@ static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
|
||||
UnlockArea.lOffset = RESERVED_BYTE;
|
||||
UnlockArea.lRange = 1L;
|
||||
rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
|
||||
OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu );
|
||||
OSTRACE(( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ));
|
||||
}
|
||||
r = !(rc == NO_ERROR);
|
||||
OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r );
|
||||
OSTRACE(( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ));
|
||||
}
|
||||
*pOut = r;
|
||||
return SQLITE_OK;
|
||||
@ -478,7 +479,7 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
|
||||
memset(&UnlockArea, 0, sizeof(UnlockArea));
|
||||
assert( pFile!=0 );
|
||||
assert( locktype<=SHARED_LOCK );
|
||||
OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
|
||||
OSTRACE(( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ));
|
||||
type = pFile->locktype;
|
||||
if( type>=EXCLUSIVE_LOCK ){
|
||||
LockArea.lOffset = 0L;
|
||||
@ -486,11 +487,11 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
|
||||
UnlockArea.lOffset = SHARED_FIRST;
|
||||
UnlockArea.lRange = SHARED_SIZE;
|
||||
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
|
||||
OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ));
|
||||
if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
|
||||
/* This should never happen. We should always be able to
|
||||
** reacquire the read lock */
|
||||
OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype );
|
||||
OSTRACE(( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ));
|
||||
rc = SQLITE_IOERR_UNLOCK;
|
||||
}
|
||||
}
|
||||
@ -500,11 +501,12 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
|
||||
UnlockArea.lOffset = RESERVED_BYTE;
|
||||
UnlockArea.lRange = 1L;
|
||||
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
|
||||
OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "UNLOCK %d reserved res=%d\n", pFile->h, res ));
|
||||
}
|
||||
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
|
||||
res = unlockReadLock(pFile);
|
||||
OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res );
|
||||
OSTRACE(( "UNLOCK %d is %d want %d res=%d\n",
|
||||
pFile->h, type, locktype, res ));
|
||||
}
|
||||
if( type>=PENDING_LOCK ){
|
||||
LockArea.lOffset = 0L;
|
||||
@ -512,10 +514,10 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
|
||||
UnlockArea.lOffset = PENDING_BYTE;
|
||||
UnlockArea.lRange = 1L;
|
||||
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
|
||||
OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res );
|
||||
OSTRACE(( "UNLOCK %d pending res=%d\n", pFile->h, res ));
|
||||
}
|
||||
pFile->locktype = locktype;
|
||||
OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype );
|
||||
OSTRACE(( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -526,7 +528,8 @@ static int os2FileControl(sqlite3_file *id, int op, void *pArg){
|
||||
switch( op ){
|
||||
case SQLITE_FCNTL_LOCKSTATE: {
|
||||
*(int*)pArg = ((os2File*)id)->locktype;
|
||||
OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
|
||||
OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
|
||||
((os2File*)id)->h, ((os2File*)id)->locktype ));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
@ -713,7 +716,7 @@ static int getTempname(int nBuf, char *zBuf ){
|
||||
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
|
||||
}
|
||||
zBuf[j] = 0;
|
||||
OSTRACE2( "TEMP FILENAME: %s\n", zBuf );
|
||||
OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -776,30 +779,30 @@ static int os2Open(
|
||||
|
||||
memset( pFile, 0, sizeof(*pFile) );
|
||||
|
||||
OSTRACE2( "OPEN want %d\n", flags );
|
||||
OSTRACE( "OPEN want %d\n", flags ));
|
||||
|
||||
if( flags & SQLITE_OPEN_READWRITE ){
|
||||
ulOpenMode |= OPEN_ACCESS_READWRITE;
|
||||
OSTRACE1( "OPEN read/write\n" );
|
||||
OSTRACE(( "OPEN read/write\n" ));
|
||||
}else{
|
||||
ulOpenMode |= OPEN_ACCESS_READONLY;
|
||||
OSTRACE1( "OPEN read only\n" );
|
||||
OSTRACE(( "OPEN read only\n" ));
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_CREATE ){
|
||||
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
|
||||
OSTRACE1( "OPEN open new/create\n" );
|
||||
OSTRACE(( "OPEN open new/create\n" ));
|
||||
}else{
|
||||
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
|
||||
OSTRACE1( "OPEN open existing\n" );
|
||||
OSTRACE(( "OPEN open existing\n" ));
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_MAIN_DB ){
|
||||
ulOpenMode |= OPEN_SHARE_DENYNONE;
|
||||
OSTRACE1( "OPEN share read/write\n" );
|
||||
OSTRACE(( "OPEN share read/write\n" ));
|
||||
}else{
|
||||
ulOpenMode |= OPEN_SHARE_DENYWRITE;
|
||||
OSTRACE1( "OPEN share read only\n" );
|
||||
OSTRACE(( "OPEN share read only\n" ));
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_DELETEONCLOSE ){
|
||||
@ -809,10 +812,10 @@ static int os2Open(
|
||||
#endif
|
||||
os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
|
||||
pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
|
||||
OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
|
||||
OSTRACE(( "OPEN hidden/delete on close file attributes\n" ));
|
||||
}else{
|
||||
pFile->pathToDel = NULL;
|
||||
OSTRACE1( "OPEN normal file attribute\n" );
|
||||
OSTRACE(( "OPEN normal file attribute\n" ));
|
||||
}
|
||||
|
||||
/* always open in random access mode for possibly better speed */
|
||||
@ -831,13 +834,14 @@ static int os2Open(
|
||||
(PEAOP2)NULL );
|
||||
free( zNameCp );
|
||||
if( rc != NO_ERROR ){
|
||||
OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
|
||||
rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode );
|
||||
OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
|
||||
rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ));
|
||||
if( pFile->pathToDel )
|
||||
free( pFile->pathToDel );
|
||||
pFile->pathToDel = NULL;
|
||||
if( flags & SQLITE_OPEN_READWRITE ){
|
||||
OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
|
||||
OSTRACE(( "OPEN %d Invalid handle\n",
|
||||
((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ));
|
||||
return os2Open( pVfs, zName, id,
|
||||
((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
|
||||
pOutFlags );
|
||||
@ -853,7 +857,7 @@ static int os2Open(
|
||||
pFile->pMethod = &os2IoMethod;
|
||||
pFile->h = h;
|
||||
OpenCounter(+1);
|
||||
OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags );
|
||||
OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -870,7 +874,7 @@ static int os2Delete(
|
||||
SimulateIOError( return SQLITE_IOERR_DELETE );
|
||||
rc = DosDelete( (PSZ)zFilenameCp );
|
||||
free( zFilenameCp );
|
||||
OSTRACE2( "DELETE \"%s\"\n", zFilename );
|
||||
OSTRACE(( "DELETE \"%s\"\n", zFilename ));
|
||||
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
|
||||
}
|
||||
|
||||
@ -891,17 +895,17 @@ static int os2Access(
|
||||
rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
|
||||
&fsts3ConfigInfo, sizeof(FILESTATUS3) );
|
||||
free( zFilenameCp );
|
||||
OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
|
||||
fsts3ConfigInfo.attrFile, flags, rc );
|
||||
OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
|
||||
fsts3ConfigInfo.attrFile, flags, rc ));
|
||||
switch( flags ){
|
||||
case SQLITE_ACCESS_READ:
|
||||
case SQLITE_ACCESS_EXISTS:
|
||||
rc = (rc == NO_ERROR);
|
||||
OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc );
|
||||
OSTRACE(( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc));
|
||||
break;
|
||||
case SQLITE_ACCESS_READWRITE:
|
||||
rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
|
||||
OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc );
|
||||
OSTRACE(( "ACCESS %s access of read/write rc=%d\n", zFilename, rc ));
|
||||
break;
|
||||
default:
|
||||
assert( !"Invalid flags argument" );
|
||||
@ -1111,7 +1115,7 @@ int sqlite3_os_init(void){
|
||||
os2Randomness, /* xRandomness */
|
||||
os2Sleep, /* xSleep */
|
||||
os2CurrentTime, /* xCurrentTime */
|
||||
os2GetLastError /* xGetLastError */
|
||||
os2GetLastError, /* xGetLastError */
|
||||
};
|
||||
sqlite3_vfs_register(&os2Vfs, 1);
|
||||
initUconvObjects();
|
||||
|
1962
src/os_unix.c
1962
src/os_unix.c
File diff suppressed because it is too large
Load Diff
945
src/os_win.c
945
src/os_win.c
File diff suppressed because it is too large
Load Diff
1865
src/pager.c
1865
src/pager.c
File diff suppressed because it is too large
Load Diff
20
src/pager.h
20
src/pager.h
@ -68,14 +68,15 @@ typedef struct PgHdr DbPage;
|
||||
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
|
||||
|
||||
/*
|
||||
** Valid values for the second argument to sqlite3PagerJournalMode().
|
||||
** Numeric constants that encode the journalmode.
|
||||
*/
|
||||
#define PAGER_JOURNALMODE_QUERY -1
|
||||
#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
|
||||
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
|
||||
#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
|
||||
#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
|
||||
@ -103,7 +104,9 @@ int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
|
||||
int sqlite3PagerLockingMode(Pager *, int);
|
||||
int sqlite3PagerJournalMode(Pager *, int);
|
||||
int sqlite3PagerSetJournalMode(Pager *, int);
|
||||
int sqlite3PagerGetJournalMode(Pager*);
|
||||
int sqlite3PagerOkToChangeJournalMode(Pager*);
|
||||
i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
|
||||
sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
|
||||
|
||||
@ -133,9 +136,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*);
|
||||
@ -147,6 +157,10 @@ int sqlite3PagerIsMemdb(Pager*);
|
||||
/* Functions used to truncate the database file. */
|
||||
void sqlite3PagerTruncateImage(Pager*,Pgno);
|
||||
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
|
||||
void *sqlite3PagerCodec(DbPage *);
|
||||
#endif
|
||||
|
||||
/* Functions to support testing and debugging. */
|
||||
#if !defined(NDEBUG) || defined(SQLITE_TEST)
|
||||
Pgno sqlite3PagerPagenumber(DbPage*);
|
||||
|
45
src/parse.y
45
src/parse.y
@ -848,23 +848,27 @@ likeop(A) ::= LIKE_KW(X). {A.eOperator = X; A.not = 0;}
|
||||
likeop(A) ::= NOT LIKE_KW(X). {A.eOperator = X; A.not = 1;}
|
||||
likeop(A) ::= MATCH(X). {A.eOperator = X; A.not = 0;}
|
||||
likeop(A) ::= NOT MATCH(X). {A.eOperator = X; A.not = 1;}
|
||||
%type escape {ExprSpan}
|
||||
%destructor escape {sqlite3ExprDelete(pParse->db, $$.pExpr);}
|
||||
escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
|
||||
escape(X) ::= . [ESCAPE] {memset(&X,0,sizeof(X));}
|
||||
expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE_KW] {
|
||||
expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE_KW] {
|
||||
ExprList *pList;
|
||||
pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
|
||||
pList = sqlite3ExprListAppend(pParse,pList, X.pExpr);
|
||||
if( E.pExpr ){
|
||||
pList = sqlite3ExprListAppend(pParse,pList, E.pExpr);
|
||||
}
|
||||
A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
|
||||
if( OP.not ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
|
||||
A.zStart = X.zStart;
|
||||
A.zEnd = Y.zEnd;
|
||||
if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
|
||||
}
|
||||
expr(A) ::= expr(X) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] {
|
||||
ExprList *pList;
|
||||
pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
|
||||
pList = sqlite3ExprListAppend(pParse,pList, X.pExpr);
|
||||
pList = sqlite3ExprListAppend(pParse,pList, E.pExpr);
|
||||
A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
|
||||
if( OP.not ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
|
||||
A.zStart = X.zStart;
|
||||
A.zEnd = E.zEnd;
|
||||
if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
|
||||
}
|
||||
|
||||
%include {
|
||||
/* Construct an expression node for a unary postfix operator
|
||||
@ -959,14 +963,27 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
in_op(A) ::= IN. {A = 0;}
|
||||
in_op(A) ::= NOT IN. {A = 1;}
|
||||
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pList = Y;
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
if( Y==0 ){
|
||||
/* Expressions of the form
|
||||
**
|
||||
** expr1 IN ()
|
||||
** expr1 NOT IN ()
|
||||
**
|
||||
** simplify to constants 0 (false) and 1 (true), respectively,
|
||||
** regardless of the value of expr1.
|
||||
*/
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
|
||||
sqlite3ExprDelete(pParse->db, X.pExpr);
|
||||
}else{
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pList = Y;
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
}
|
||||
if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
|
||||
}
|
||||
if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
|
||||
A.zStart = X.zStart;
|
||||
A.zEnd = &E.z[E.n];
|
||||
}
|
||||
|
17
src/pcache.c
17
src/pcache.c
@ -260,15 +260,17 @@ int sqlite3PcacheFetch(
|
||||
|
||||
if( pPage ){
|
||||
if( !pPage->pData ){
|
||||
memset(pPage, 0, sizeof(PgHdr) + pCache->szExtra);
|
||||
pPage->pExtra = (void*)&pPage[1];
|
||||
pPage->pData = (void *)&((char *)pPage)[sizeof(PgHdr) + pCache->szExtra];
|
||||
memset(pPage, 0, sizeof(PgHdr));
|
||||
pPage->pData = (void *)&pPage[1];
|
||||
pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage];
|
||||
memset(pPage->pExtra, 0, pCache->szExtra);
|
||||
pPage->pCache = pCache;
|
||||
pPage->pgno = pgno;
|
||||
}
|
||||
assert( pPage->pCache==pCache );
|
||||
assert( pPage->pgno==pgno );
|
||||
assert( pPage->pExtra==(void *)&pPage[1] );
|
||||
assert( pPage->pData==(void *)&pPage[1] );
|
||||
assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] );
|
||||
|
||||
if( 0==pPage->nRef ){
|
||||
pCache->nRef++;
|
||||
@ -407,7 +409,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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
@ -712,7 +716,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
|
||||
** already provided an alternative.
|
||||
*/
|
||||
void sqlite3PCacheSetDefault(void){
|
||||
static sqlite3_pcache_methods defaultMethods = {
|
||||
static const sqlite3_pcache_methods defaultMethods = {
|
||||
0, /* pArg */
|
||||
pcache1Init, /* xInit */
|
||||
pcache1Shutdown, /* xShutdown */
|
||||
|
159
src/pragma.c
159
src/pragma.c
@ -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,62 +531,49 @@ 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 */
|
||||
int ii; /* Loop counter */
|
||||
|
||||
if( zRight==0 ){
|
||||
eMode = PAGER_JOURNALMODE_QUERY;
|
||||
}else{
|
||||
int n = sqlite3Strlen30(zRight);
|
||||
eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1;
|
||||
while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){
|
||||
eMode--;
|
||||
}
|
||||
/* Force the schema to be loaded on all databases. This cases all
|
||||
** database files to be opened and the journal_modes set. */
|
||||
if( sqlite3ReadSchema(pParse) ){
|
||||
goto pragma_out;
|
||||
}
|
||||
if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
|
||||
/* Simple "PRAGMA journal_mode;" statement. This is a query for
|
||||
** the current default journal mode (which may be different to
|
||||
** the journal-mode of the main database).
|
||||
*/
|
||||
eMode = db->dfltJournalMode;
|
||||
}else{
|
||||
Pager *pPager;
|
||||
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.
|
||||
**
|
||||
** 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);
|
||||
}
|
||||
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);
|
||||
|
||||
if( zRight==0 ){
|
||||
/* If there is no "=MODE" part of the pragma, do a query for the
|
||||
** current mode */
|
||||
eMode = PAGER_JOURNALMODE_QUERY;
|
||||
}else{
|
||||
const char *zMode;
|
||||
int n = sqlite3Strlen30(zRight);
|
||||
for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){
|
||||
if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
|
||||
}
|
||||
if( !zMode ){
|
||||
/* If the "=MODE" part does not match any known journal mode,
|
||||
** then do a query */
|
||||
eMode = PAGER_JOURNALMODE_QUERY;
|
||||
}
|
||||
}
|
||||
if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){
|
||||
/* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */
|
||||
iDb = 0;
|
||||
pId2->n = 1;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}else
|
||||
|
||||
@ -1380,6 +1391,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
|
||||
|
@ -73,15 +73,18 @@ 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;
|
||||
TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
|
||||
|
||||
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);
|
||||
TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
|
||||
rc = db->errCode;
|
||||
assert( (rc&0xFF)==(rcp&0xFF) );
|
||||
db->init.iDb = 0;
|
||||
assert( rc!=SQLITE_OK || zErr==0 );
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( db->init.orphanTrigger ){
|
||||
assert( iDb==1 );
|
||||
@ -89,12 +92,12 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
pData->rc = rc;
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
|
||||
corruptSchema(pData, argv[0], zErr);
|
||||
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
|
||||
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 +582,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 +604,7 @@ static int sqlite3Prepare(
|
||||
}else{
|
||||
sqlite3RunParser(pParse, zSql, &zErrMsg);
|
||||
}
|
||||
assert( 1==(int)pParse->nQueryLoop );
|
||||
|
||||
if( db->mallocFailed ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
|
@ -357,6 +357,7 @@ static int lookupName(
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
pTopNC->nErr++;
|
||||
}
|
||||
|
||||
@ -403,7 +404,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 +416,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);
|
||||
|
31
src/select.c
31
src/select.c
@ -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) */
|
||||
@ -3020,6 +3020,7 @@ int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
|
||||
);
|
||||
if( !pIdx ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0);
|
||||
pParse->checkSchema = 1;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pFrom->pIndex = pIdx;
|
||||
@ -3498,6 +3499,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 +3719,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
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
341
src/sqlite.h.in
341
src/sqlite.h.in
@ -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
|
||||
@ -388,7 +388,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
|
||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||
#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
|
||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||
#define SQLITE_EMPTY 16 /* Database is empty */
|
||||
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
|
||||
@ -444,7 +444,12 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
|
||||
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
|
||||
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
|
||||
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )
|
||||
#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
|
||||
#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
|
||||
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
|
||||
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags For File Open Operations
|
||||
@ -471,11 +476,12 @@ int sqlite3_exec(
|
||||
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
|
||||
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
|
||||
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Device Characteristics
|
||||
**
|
||||
** The xDeviceCapabilities method of the [sqlite3_io_methods]
|
||||
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
|
||||
** object returns an integer which is a vector of the these
|
||||
** bit values expressing I/O characteristics of the mass storage
|
||||
** device that holds the file that the [sqlite3_io_methods]
|
||||
@ -492,17 +498,18 @@ int sqlite3_exec(
|
||||
** information is written to disk in the same order as calls
|
||||
** to xWrite().
|
||||
*/
|
||||
#define SQLITE_IOCAP_ATOMIC 0x00000001
|
||||
#define SQLITE_IOCAP_ATOMIC512 0x00000002
|
||||
#define SQLITE_IOCAP_ATOMIC1K 0x00000004
|
||||
#define SQLITE_IOCAP_ATOMIC2K 0x00000008
|
||||
#define SQLITE_IOCAP_ATOMIC4K 0x00000010
|
||||
#define SQLITE_IOCAP_ATOMIC8K 0x00000020
|
||||
#define SQLITE_IOCAP_ATOMIC16K 0x00000040
|
||||
#define SQLITE_IOCAP_ATOMIC32K 0x00000080
|
||||
#define SQLITE_IOCAP_ATOMIC64K 0x00000100
|
||||
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
|
||||
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
|
||||
#define SQLITE_IOCAP_ATOMIC 0x00000001
|
||||
#define SQLITE_IOCAP_ATOMIC512 0x00000002
|
||||
#define SQLITE_IOCAP_ATOMIC1K 0x00000004
|
||||
#define SQLITE_IOCAP_ATOMIC2K 0x00000008
|
||||
#define SQLITE_IOCAP_ATOMIC4K 0x00000010
|
||||
#define SQLITE_IOCAP_ATOMIC8K 0x00000020
|
||||
#define SQLITE_IOCAP_ATOMIC16K 0x00000040
|
||||
#define SQLITE_IOCAP_ATOMIC32K 0x00000080
|
||||
#define SQLITE_IOCAP_ATOMIC64K 0x00000100
|
||||
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
|
||||
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
|
||||
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
|
||||
|
||||
/*
|
||||
** CAPI3REF: File Locking Levels
|
||||
@ -653,6 +660,12 @@ 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 (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
|
||||
int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
|
||||
void (*xShmBarrier)(sqlite3_file*);
|
||||
int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
|
||||
/* Methods above are valid for version 2 */
|
||||
/* Additional methods may be added in future releases */
|
||||
};
|
||||
|
||||
@ -670,11 +683,19 @@ struct sqlite3_io_methods {
|
||||
** into an integer that the pArg argument points to. This capability
|
||||
** is used during testing and only needs to be supported when SQLITE_TEST
|
||||
** is defined.
|
||||
**
|
||||
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
|
||||
** layer a hint of how large the database file will grow to be during the
|
||||
** current transaction. This hint is not guaranteed to be accurate but it
|
||||
** is often close. The underlying VFS might choose to preallocate database
|
||||
** file space based on this hint in order to help writes to the database
|
||||
** file run faster.
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_GET_LOCKPROXYFILE 2
|
||||
#define SQLITE_SET_LOCKPROXYFILE 3
|
||||
#define SQLITE_LAST_ERRNO 4
|
||||
#define SQLITE_FCNTL_SIZE_HINT 5
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Handle
|
||||
@ -806,20 +827,27 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
||||
** handled as a fatal error by SQLite, vfs implementations should endeavor
|
||||
** to prevent this by setting mxPathname to a sufficiently large value.
|
||||
**
|
||||
** The xRandomness(), xSleep(), and xCurrentTime() interfaces
|
||||
** are not strictly a part of the filesystem, but they are
|
||||
** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64()
|
||||
** interfaces are not strictly a part of the filesystem, but they are
|
||||
** included in the VFS structure for completeness.
|
||||
** The xRandomness() function attempts to return nBytes bytes
|
||||
** of good-quality randomness into zOut. The return value is
|
||||
** the actual number of bytes of randomness obtained.
|
||||
** The xSleep() method causes the calling thread to sleep for at
|
||||
** least the number of microseconds given. The xCurrentTime()
|
||||
** method returns a Julian Day Number for the current date and time.
|
||||
**
|
||||
** method returns a Julian Day Number for the current date and time as
|
||||
** a floating point value.
|
||||
** The xCurrentTimeInt64() method returns, as an integer, the Julian
|
||||
** Day Number multipled by 86400000 (the number of milliseconds in
|
||||
** a 24-hour day).
|
||||
** ^SQLite will use the xCurrentTimeInt64() method to get the current
|
||||
** date and time if that method is available (if iVersion is 2 or
|
||||
** greater and the function pointer is not NULL) and will fall back
|
||||
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
|
||||
*/
|
||||
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 +866,16 @@ 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 (*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.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
@ -851,13 +887,58 @@ struct sqlite3_vfs {
|
||||
** With SQLITE_ACCESS_EXISTS, the xAccess method
|
||||
** simply checks whether the file exists.
|
||||
** With SQLITE_ACCESS_READWRITE, the xAccess method
|
||||
** checks whether the file is both readable and writable.
|
||||
** checks whether the named directory is both readable and writable
|
||||
** (in other words, if files can be added, removed, and renamed within
|
||||
** the directory).
|
||||
** The SQLITE_ACCESS_READWRITE constant is currently used only by the
|
||||
** [temp_store_directory pragma], though this could change in a future
|
||||
** release of SQLite.
|
||||
** With SQLITE_ACCESS_READ, the xAccess method
|
||||
** checks whether the file is readable.
|
||||
** checks whether the file is readable. The SQLITE_ACCESS_READ constant is
|
||||
** currently unused, though it might be used in a future release of
|
||||
** SQLite.
|
||||
*/
|
||||
#define SQLITE_ACCESS_EXISTS 0
|
||||
#define SQLITE_ACCESS_READWRITE 1
|
||||
#define SQLITE_ACCESS_READ 2
|
||||
#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */
|
||||
#define SQLITE_ACCESS_READ 2 /* Unused */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags for the xShmLock VFS method
|
||||
**
|
||||
** These integer constants define the various locking operations
|
||||
** allowed by the xShmLock method of [sqlite3_io_methods]. The
|
||||
** following are the only legal combinations of flags to the
|
||||
** xShmLock method:
|
||||
**
|
||||
** <ul>
|
||||
** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED
|
||||
** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE
|
||||
** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED
|
||||
** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE
|
||||
** </ul>
|
||||
**
|
||||
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
|
||||
** was given no the corresponding lock.
|
||||
**
|
||||
** The xShmLock method can transition between unlocked and SHARED or
|
||||
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
|
||||
** and EXCLUSIVE.
|
||||
*/
|
||||
#define SQLITE_SHM_UNLOCK 1
|
||||
#define SQLITE_SHM_LOCK 2
|
||||
#define SQLITE_SHM_SHARED 4
|
||||
#define SQLITE_SHM_EXCLUSIVE 8
|
||||
|
||||
/*
|
||||
** CAPI3REF: Maximum xShmLock index
|
||||
**
|
||||
** The xShmLock method on [sqlite3_io_methods] may use values
|
||||
** between 0 and this upper bound as its "offset" argument.
|
||||
** The SQLite core will never attempt to acquire or release a
|
||||
** lock outside of this range
|
||||
*/
|
||||
#define SQLITE_SHM_NLOCK 8
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Initialize The SQLite Library
|
||||
@ -968,11 +1049,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 +1072,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 +1157,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 +1342,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 +1380,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 +2156,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 +2173,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 +2966,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 +3786,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 +3969,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 +4254,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 +4273,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 +4319,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 +4400,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 +4421,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 +4438,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 +4463,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 +4484,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 +4508,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 +4518,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 +4860,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.
|
||||
@ -4984,11 +5072,11 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_RESERVE 14
|
||||
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
||||
#define SQLITE_TESTCTRL_ISKEYWORD 16
|
||||
#define SQLITE_TESTCTRL_LAST 16
|
||||
#define SQLITE_TESTCTRL_PGHDRSZ 17
|
||||
#define SQLITE_TESTCTRL_LAST 17
|
||||
|
||||
/*
|
||||
** 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 +5104,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 +5195,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 +5212,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 +5230,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.
|
||||
** </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 +5266,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 +5287,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 +5316,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 +5457,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 +5469,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 +5537,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 +5660,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 +5781,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 +5791,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 +5812,89 @@ 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 [ATTACH]-ed 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. If the
|
||||
** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value
|
||||
** that does not correspond to any valid SQLite error code, the results
|
||||
** are undefined.
|
||||
**
|
||||
** 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.
|
||||
|
@ -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)).
|
||||
@ -272,6 +272,13 @@
|
||||
# define NEVER(X) (X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if the input is a integer that is too large
|
||||
** to fit in 32-bits. This macro is used inside of various testcase()
|
||||
** macros to verify that we have tested SQLite for large-file support.
|
||||
*/
|
||||
#define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0)
|
||||
|
||||
/*
|
||||
** The macro unlikely() is a hint that surrounds a boolean
|
||||
** expression that is usually false. Macro likely() surrounds
|
||||
@ -301,6 +308,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)
|
||||
@ -789,7 +797,6 @@ struct sqlite3 {
|
||||
u8 temp_store; /* 1: file 2: memory 0: default */
|
||||
u8 mallocFailed; /* True if we have seen a malloc failure */
|
||||
u8 dfltLockMode; /* Default locking-mode for attached dbs */
|
||||
u8 dfltJournalMode; /* Default journal mode for attached dbs */
|
||||
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
|
||||
u8 suppressErr; /* Do not issue error messages if true */
|
||||
int nextPagesize; /* Pagesize after VACUUM if >0 */
|
||||
@ -822,6 +829,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 +922,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 +935,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 +1787,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 +1901,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 +1924,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 +2166,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 */
|
||||
@ -2523,7 +2542,8 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
|
||||
|
||||
|
||||
#ifndef SQLITE_MUTEX_OMIT
|
||||
sqlite3_mutex_methods *sqlite3DefaultMutex(void);
|
||||
sqlite3_mutex_methods const *sqlite3DefaultMutex(void);
|
||||
sqlite3_mutex_methods const *sqlite3NoopMutex(void);
|
||||
sqlite3_mutex *sqlite3MutexAlloc(int);
|
||||
int sqlite3MutexInit(void);
|
||||
int sqlite3MutexEnd(void);
|
||||
@ -2655,6 +2675,7 @@ void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
|
||||
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
||||
void sqlite3ExprCodeCopy(Parse*, int, int, int);
|
||||
void sqlite3ExprCacheStore(Parse*, int, int, int);
|
||||
@ -2681,6 +2702,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*);
|
||||
@ -2868,13 +2890,16 @@ void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
||||
extern const unsigned char sqlite3OpcodeProperty[];
|
||||
extern const unsigned char sqlite3UpperToLower[];
|
||||
extern const unsigned char sqlite3CtypeMap[];
|
||||
extern const Token sqlite3IntTokens[];
|
||||
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
|
||||
extern SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
extern int sqlite3PendingByte;
|
||||
#endif
|
||||
#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 +3008,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 +3117,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
|
||||
|
20
src/status.c
20
src/status.c
@ -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;
|
||||
}
|
||||
|
138
src/tclsqlite.c
138
src/tclsqlite.c
@ -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;
|
||||
}
|
||||
@ -2855,8 +2897,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
if( strcmp(zArg,"-key")==0 ){
|
||||
pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
|
||||
}else if( strcmp(zArg, "-vfs")==0 ){
|
||||
i++;
|
||||
zVfs = Tcl_GetString(objv[i]);
|
||||
zVfs = Tcl_GetString(objv[i+1]);
|
||||
}else if( strcmp(zArg, "-readonly")==0 ){
|
||||
int b;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
|
||||
@ -3447,22 +3488,55 @@ static char zMainloop[] =
|
||||
"}\n"
|
||||
;
|
||||
#endif
|
||||
#if TCLSH==2
|
||||
static char zMainloop[] =
|
||||
#include "spaceanal_tcl.h"
|
||||
;
|
||||
#endif
|
||||
|
||||
#define TCLSH_MAIN main /* Needed to fake out mktclapp */
|
||||
int TCLSH_MAIN(int argc, char **argv){
|
||||
Tcl_Interp *interp;
|
||||
|
||||
/* Call sqlite3_shutdown() once before doing anything else. This is to
|
||||
** test that sqlite3_shutdown() can be safely called by a process before
|
||||
** sqlite3_initialize() is. */
|
||||
sqlite3_shutdown();
|
||||
#ifdef SQLITE_TEST
|
||||
static void init_all(Tcl_Interp *);
|
||||
static int init_all_cmd(
|
||||
ClientData cd,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
|
||||
Tcl_FindExecutable(argv[0]);
|
||||
interp = Tcl_CreateInterp();
|
||||
Tcl_Interp *slave;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SLAVE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
|
||||
if( !slave ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
init_all(slave);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Configure the interpreter passed as the first argument to have access
|
||||
** to the commands and linked variables that make up:
|
||||
**
|
||||
** * the [sqlite3] extension itself,
|
||||
**
|
||||
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
|
||||
**
|
||||
** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
|
||||
** test suite.
|
||||
*/
|
||||
static void init_all(Tcl_Interp *interp){
|
||||
Sqlite3_Init(interp);
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5)
|
||||
Md5_Init(interp);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
{
|
||||
extern int Sqliteconfig_Init(Tcl_Interp*);
|
||||
@ -3477,6 +3551,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 +3565,8 @@ 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 *);
|
||||
extern int SqlitetestStat_Init(Tcl_Interp*);
|
||||
|
||||
Sqliteconfig_Init(interp);
|
||||
Sqlitetest1_Init(interp);
|
||||
@ -3503,6 +3580,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,12 +3593,34 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
SqlitetestOsinst_Init(interp);
|
||||
Sqlitetestbackup_Init(interp);
|
||||
Sqlitetestintarray_Init(interp);
|
||||
Sqlitetestvfs_Init(interp);
|
||||
SqlitetestStat_Init(interp);
|
||||
|
||||
Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0);
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
Sqlitetestsse_Init(interp);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TCLSH_MAIN main /* Needed to fake out mktclapp */
|
||||
int TCLSH_MAIN(int argc, char **argv){
|
||||
Tcl_Interp *interp;
|
||||
|
||||
/* Call sqlite3_shutdown() once before doing anything else. This is to
|
||||
** test that sqlite3_shutdown() can be safely called by a process before
|
||||
** sqlite3_initialize() is. */
|
||||
sqlite3_shutdown();
|
||||
|
||||
#if TCLSH==2
|
||||
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
||||
#endif
|
||||
Tcl_FindExecutable(argv[0]);
|
||||
|
||||
interp = Tcl_CreateInterp();
|
||||
init_all(interp);
|
||||
if( argc>=2 ){
|
||||
int i;
|
||||
char zArgc[32];
|
||||
@ -3532,14 +3632,14 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
Tcl_SetVar(interp, "argv", argv[i],
|
||||
TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
|
||||
}
|
||||
if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
|
||||
if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
|
||||
const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
|
||||
if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp);
|
||||
fprintf(stderr,"%s: %s\n", *argv, zInfo);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( argc<=1 ){
|
||||
if( TCLSH==2 || argc<=1 ){
|
||||
Tcl_GlobalEval(interp, zMainloop);
|
||||
}
|
||||
return 0;
|
||||
|
71
src/test1.c
71
src/test1.c
@ -1901,6 +1901,13 @@ static int sqlite_abort(
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
#if defined(_MSC_VER)
|
||||
/* We do this, otherwise the test will halt with a popup message
|
||||
* that we have to click away before the test will continue.
|
||||
*/
|
||||
_set_abort_behavior( 0, _CALL_REPORTFAULT );
|
||||
#endif
|
||||
exit(255);
|
||||
assert( interp==0 ); /* This will always fail */
|
||||
return TCL_OK;
|
||||
}
|
||||
@ -2025,6 +2032,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");
|
||||
@ -2625,7 +2633,7 @@ bad_args:
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: test_errstr <err code>
|
||||
** Usage: sqlite3_test_errstr <err code>
|
||||
**
|
||||
** Test that the english language string equivalents for sqlite error codes
|
||||
** are sane. The parameter is an integer representing an sqlite error code.
|
||||
@ -3899,7 +3907,6 @@ static int test_global_recover(
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
int rc;
|
||||
if( objc!=1 ){
|
||||
@ -3908,7 +3915,6 @@ static int test_global_recover(
|
||||
}
|
||||
rc = sqlite3_global_recover();
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
#endif
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
@ -4608,7 +4614,7 @@ static int file_control_lasterrno_test(
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_lockproxy_test DB
|
||||
** tclcmd: file_control_lockproxy_test DB PWD
|
||||
**
|
||||
** This TCL command runs the sqlite3_file_control interface and
|
||||
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
|
||||
@ -4621,15 +4627,18 @@ static int file_control_lockproxy_test(
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zPwd;
|
||||
int nPwd;
|
||||
|
||||
if( objc!=2 ){
|
||||
if( objc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
|
||||
Tcl_GetStringFromObj(objv[0], 0), " DB PWD", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zPwd = Tcl_GetStringFromObj(objv[2], &nPwd);
|
||||
|
||||
#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
|
||||
# if defined(__APPLE__)
|
||||
@ -4640,9 +4649,15 @@ static int file_control_lockproxy_test(
|
||||
#endif
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
|
||||
{
|
||||
char *proxyPath = "test.proxy";
|
||||
char *testPath;
|
||||
int rc;
|
||||
char proxyPath[400];
|
||||
|
||||
if( sizeof(proxyPath)<nPwd+20 ){
|
||||
Tcl_AppendResult(interp, "PWD too big", (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sprintf(proxyPath, "%s/test.proxy", zPwd);
|
||||
rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
|
||||
if( rc ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
@ -4867,6 +4882,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 +5132,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;
|
||||
@ -5098,9 +5143,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
extern int sqlite3_pager_readdb_count;
|
||||
extern int sqlite3_pager_writedb_count;
|
||||
extern int sqlite3_pager_writej_count;
|
||||
#if defined(__linux__) && defined(SQLITE_TEST) && SQLITE_THREADSAFE
|
||||
extern int threadsOverrideEachOthersLocks;
|
||||
#endif
|
||||
#if SQLITE_OS_WIN
|
||||
extern int sqlite3_os_type;
|
||||
#endif
|
||||
@ -5108,6 +5150,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
extern int sqlite3WhereTrace;
|
||||
extern int sqlite3OSTrace;
|
||||
extern int sqlite3VdbeAddopTrace;
|
||||
extern int sqlite3WalTrace;
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
extern char sqlite3_query_plan[];
|
||||
@ -5156,10 +5199,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
Tcl_LinkVar(interp, "unaligned_string_counter",
|
||||
(char*)&unaligned_string_counter, TCL_LINK_INT);
|
||||
#endif
|
||||
#if defined(__linux__) && defined(SQLITE_TEST) && SQLITE_THREADSAFE
|
||||
Tcl_LinkVar(interp, "threadsOverrideEachOthersLocks",
|
||||
(char*)&threadsOverrideEachOthersLocks, TCL_LINK_INT);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
Tcl_LinkVar(interp, "sqlite_last_needed_collation",
|
||||
(char*)&pzNeededCollation, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
|
||||
@ -5179,6 +5218,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
(char*)&sqlite3WhereTrace, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_os_trace",
|
||||
(char*)&sqlite3OSTrace, TCL_LINK_INT);
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
Tcl_LinkVar(interp, "sqlite_wal_trace",
|
||||
(char*)&sqlite3WalTrace, TCL_LINK_INT);
|
||||
#endif
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
Tcl_LinkVar(interp, "sqlite_opentemp_count",
|
||||
|
@ -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);
|
||||
@ -674,7 +675,9 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
|
||||
(char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_diskfull",
|
||||
(char*)&sqlite3_diskfull, TCL_LINK_INT);
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
Tcl_LinkVar(interp, "sqlite_pending_byte",
|
||||
(char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
|
38
src/test6.c
38
src/test6.c
@ -171,7 +171,7 @@ static void *crash_realloc(void *p, int n){
|
||||
** 512 byte block begining at offset PENDING_BYTE.
|
||||
*/
|
||||
static int writeDbFile(CrashFile *p, u8 *z, i64 iAmt, i64 iOff){
|
||||
int rc;
|
||||
int rc = SQLITE_OK;
|
||||
int iSkip = 0;
|
||||
if( iOff==PENDING_BYTE && (p->flags&SQLITE_OPEN_MAIN_DB) ){
|
||||
iSkip = 512;
|
||||
@ -520,8 +520,30 @@ static int cfDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return g.iDeviceCharacteristics;
|
||||
}
|
||||
|
||||
/*
|
||||
** Pass-throughs for WAL support.
|
||||
*/
|
||||
static int cfShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
|
||||
return sqlite3OsShmLock(((CrashFile*)pFile)->pRealFile, ofst, n, flags);
|
||||
}
|
||||
static void cfShmBarrier(sqlite3_file *pFile){
|
||||
sqlite3OsShmBarrier(((CrashFile*)pFile)->pRealFile);
|
||||
}
|
||||
static int cfShmUnmap(sqlite3_file *pFile, int delFlag){
|
||||
return sqlite3OsShmUnmap(((CrashFile*)pFile)->pRealFile, delFlag);
|
||||
}
|
||||
static int cfShmMap(
|
||||
sqlite3_file *pFile, /* Handle open on database file */
|
||||
int iRegion, /* Region to retrieve */
|
||||
int sz, /* Size of regions */
|
||||
int w, /* True to extend file if necessary */
|
||||
void volatile **pp /* OUT: Mapped memory */
|
||||
){
|
||||
return sqlite3OsShmMap(((CrashFile*)pFile)->pRealFile, iRegion, sz, w, pp);
|
||||
}
|
||||
|
||||
static const sqlite3_io_methods CrashFileVtab = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
cfClose, /* xClose */
|
||||
cfRead, /* xRead */
|
||||
cfWrite, /* xWrite */
|
||||
@ -533,7 +555,11 @@ static const sqlite3_io_methods CrashFileVtab = {
|
||||
cfCheckReservedLock, /* xCheckReservedLock */
|
||||
cfFileControl, /* xFileControl */
|
||||
cfSectorSize, /* xSectorSize */
|
||||
cfDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
cfDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
cfShmMap, /* xShmMap */
|
||||
cfShmLock, /* xShmLock */
|
||||
cfShmBarrier, /* xShmBarrier */
|
||||
cfShmUnmap /* xShmUnmap */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -764,7 +790,7 @@ static int crashEnableCmd(
|
||||
){
|
||||
int isEnable;
|
||||
static sqlite3_vfs crashVfs = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
0, /* szOsFile */
|
||||
0, /* mxPathname */
|
||||
0, /* pNext */
|
||||
@ -781,7 +807,9 @@ static int crashEnableCmd(
|
||||
cfDlClose, /* xDlClose */
|
||||
cfRandomness, /* xRandomness */
|
||||
cfSleep, /* xSleep */
|
||||
cfCurrentTime /* xCurrentTime */
|
||||
cfCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetlastError */
|
||||
0, /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
if( objc!=2 ){
|
||||
|
@ -84,6 +84,7 @@ static Tcl_ThreadCreateType tclWriterThread(ClientData pIsStarted){
|
||||
*((int *)pIsStarted) = 1;
|
||||
sqlite3async_run();
|
||||
Tcl_MutexUnlock(&testasync_g_writerMutex);
|
||||
Tcl_ExitThread(0);
|
||||
TCL_THREAD_CREATE_RETURN;
|
||||
}
|
||||
|
||||
@ -228,7 +229,7 @@ static int testAsyncControl(
|
||||
** of this module.
|
||||
*/
|
||||
int Sqlitetestasync_Init(Tcl_Interp *interp){
|
||||
#if SQLITE_ENABLE_ASYNCIO
|
||||
#ifdef SQLITE_ENABLE_ASYNCIO
|
||||
Tcl_CreateObjCommand(interp,"sqlite3async_start",testAsyncStart,0,0);
|
||||
Tcl_CreateObjCommand(interp,"sqlite3async_wait",testAsyncWait,0,0);
|
||||
|
||||
|
@ -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
|
||||
@ -279,12 +285,6 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "gettable", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_GLOBALRECOVER
|
||||
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ICU
|
||||
Tcl_SetVar2(interp, "sqlite_options", "icu", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@ -463,7 +463,7 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
|
||||
Tcl_SetVar2(interp, "sqlite_options", "trigger", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_TRUCATE_OPTIMIZATION
|
||||
#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "1", TCL_GLOBAL_ONLY);
|
||||
@ -493,6 +493,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
|
||||
|
671
src/test_demovfs.c
Normal file
671
src/test_demovfs.c
Normal file
@ -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 */
|
@ -50,6 +50,10 @@ 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 devsymShmLock(sqlite3_file*,int,int,int);
|
||||
static int devsymShmMap(sqlite3_file*,int,int,int, void volatile **);
|
||||
static void devsymShmBarrier(sqlite3_file*);
|
||||
static int devsymShmUnmap(sqlite3_file*,int);
|
||||
|
||||
/*
|
||||
** Method declarations for devsym_vfs.
|
||||
@ -69,7 +73,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 +96,13 @@ static sqlite3_vfs devsym_vfs = {
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
devsymRandomness, /* xRandomness */
|
||||
devsymSleep, /* xSleep */
|
||||
devsymCurrentTime /* xCurrentTime */
|
||||
devsymCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetLastError */
|
||||
0 /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
static sqlite3_io_methods devsym_io_methods = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
devsymClose, /* xClose */
|
||||
devsymRead, /* xRead */
|
||||
devsymWrite, /* xWrite */
|
||||
@ -108,7 +114,11 @@ static sqlite3_io_methods devsym_io_methods = {
|
||||
devsymCheckReservedLock, /* xCheckReservedLock */
|
||||
devsymFileControl, /* xFileControl */
|
||||
devsymSectorSize, /* xSectorSize */
|
||||
devsymDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
devsymShmMap, /* xShmMap */
|
||||
devsymShmLock, /* xShmLock */
|
||||
devsymShmBarrier, /* xShmBarrier */
|
||||
devsymShmUnmap /* xShmUnmap */
|
||||
};
|
||||
|
||||
struct DevsymGlobal {
|
||||
@ -222,6 +232,34 @@ static int devsymDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return g.iDeviceChar;
|
||||
}
|
||||
|
||||
/*
|
||||
** Shared-memory methods are all pass-thrus.
|
||||
*/
|
||||
static int devsymShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmLock(p->pReal, ofst, n, flags);
|
||||
}
|
||||
static int devsymShmMap(
|
||||
sqlite3_file *pFile,
|
||||
int iRegion,
|
||||
int szRegion,
|
||||
int isWrite,
|
||||
void volatile **pp
|
||||
){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
|
||||
}
|
||||
static void devsymShmBarrier(sqlite3_file *pFile){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
sqlite3OsShmBarrier(p->pReal);
|
||||
}
|
||||
static int devsymShmUnmap(sqlite3_file *pFile, int delFlag){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsShmUnmap(p->pReal, delFlag);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Open an devsym file handle.
|
||||
*/
|
||||
@ -330,9 +368,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 +385,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,9 +161,10 @@ static void jtDlClose(sqlite3_vfs*, void*);
|
||||
static int jtRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
static int jtSleep(sqlite3_vfs*, int microseconds);
|
||||
static int jtCurrentTime(sqlite3_vfs*, double*);
|
||||
static int jtCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
||||
|
||||
static sqlite3_vfs jt_vfs = {
|
||||
1, /* iVersion */
|
||||
2, /* iVersion */
|
||||
sizeof(jt_file), /* szOsFile */
|
||||
JT_MAX_PATHNAME, /* mxPathname */
|
||||
0, /* pNext */
|
||||
@ -179,7 +180,9 @@ static sqlite3_vfs jt_vfs = {
|
||||
jtDlClose, /* xDlClose */
|
||||
jtRandomness, /* xRandomness */
|
||||
jtSleep, /* xSleep */
|
||||
jtCurrentTime /* xCurrentTime */
|
||||
jtCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetLastError */
|
||||
jtCurrentTimeInt64 /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
static sqlite3_io_methods jt_io_methods = {
|
||||
@ -801,7 +804,13 @@ 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);
|
||||
}
|
||||
/*
|
||||
** Return the current time as a Julian Day number in *pTimeOut.
|
||||
*/
|
||||
static int jtCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
|
||||
return g.pVfs->xCurrentTimeInt64(g.pVfs, pTimeOut);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -821,6 +830,11 @@ int jt_register(char *zWrap, int isDefault){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
jt_vfs.szOsFile = sizeof(jt_file) + g.pVfs->szOsFile;
|
||||
if( g.pVfs->iVersion==1 ){
|
||||
jt_vfs.iVersion = 1;
|
||||
}else if( g.pVfs->xCurrentTimeInt64==0 ){
|
||||
jt_vfs.xCurrentTimeInt64 = 0;
|
||||
}
|
||||
sqlite3_vfs_register(&jt_vfs, isDefault);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -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 ){
|
||||
@ -1358,6 +1359,25 @@ static int test_install_memsys3(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_vfs_oom_test(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
extern int sqlite3_memdebug_vfs_oom_test;
|
||||
if( objc>2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
|
||||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
int iNew;
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
|
||||
sqlite3_memdebug_vfs_oom_test = iNew;
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
@ -1395,6 +1415,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
|
||||
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
|
||||
{ "sqlite3_install_memsys3", test_install_memsys3 ,0 },
|
||||
{ "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
|
@ -198,7 +198,8 @@ static fs_vfs_t fs_vfs = {
|
||||
fsDlClose, /* xDlClose */
|
||||
fsRandomness, /* xRandomness */
|
||||
fsSleep, /* xSleep */
|
||||
fsCurrentTime /* xCurrentTime */
|
||||
fsCurrentTime, /* xCurrentTime */
|
||||
0 /* xCurrentTimeInt64 */
|
||||
},
|
||||
0, /* pFileList */
|
||||
0 /* pParent */
|
||||
@ -217,7 +218,11 @@ static sqlite3_io_methods fs_io_methods = {
|
||||
fsCheckReservedLock, /* xCheckReservedLock */
|
||||
fsFileControl, /* xFileControl */
|
||||
fsSectorSize, /* xSectorSize */
|
||||
fsDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
fsDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
0, /* xShmMap */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmBarrier */
|
||||
0 /* xShmUnmap */
|
||||
};
|
||||
|
||||
|
||||
@ -234,7 +239,11 @@ static sqlite3_io_methods tmp_io_methods = {
|
||||
tmpCheckReservedLock, /* xCheckReservedLock */
|
||||
tmpFileControl, /* xFileControl */
|
||||
tmpSectorSize, /* xSectorSize */
|
||||
tmpDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
tmpDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
0, /* xShmMap */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmBarrier */
|
||||
0 /* xShmUnmap */
|
||||
};
|
||||
|
||||
/* Useful macros used in several places */
|
||||
|
1628
src/test_osinst.c
1628
src/test_osinst.c
File diff suppressed because it is too large
Load Diff
609
src/test_stat.c
Normal file
609
src/test_stat.c
Normal file
@ -0,0 +1,609 @@
|
||||
/*
|
||||
** 2010 July 12
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains an implementation of the "dbstat" virtual table.
|
||||
**
|
||||
** The dbstat virtual table is used to extract low-level formatting
|
||||
** information from an SQLite database in order to implement the
|
||||
** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
|
||||
** for an example implementation.
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Page paths:
|
||||
**
|
||||
** The value of the 'path' column describes the path taken from the
|
||||
** root-node of the b-tree structure to each page. The value of the
|
||||
** root-node path is '/'.
|
||||
**
|
||||
** The value of the path for the left-most child page of the root of
|
||||
** a b-tree is '/000/'. (Btrees store content ordered from left to right
|
||||
** so the pages to the left have smaller keys than the pages to the right.)
|
||||
** The next to left-most child of the root page is
|
||||
** '/001', and so on, each sibling page identified by a 3-digit hex
|
||||
** value. The children of the 451st left-most sibling have paths such
|
||||
** as '/1c2/000/, '/1c2/001/' etc.
|
||||
**
|
||||
** Overflow pages are specified by appending a '+' character and a
|
||||
** six-digit hexadecimal value to the path to the cell they are linked
|
||||
** from. For example, the three overflow pages in a chain linked from
|
||||
** the left-most cell of the 450th child of the root page are identified
|
||||
** by the paths:
|
||||
**
|
||||
** '/1c2/000+000000' // First page in overflow chain
|
||||
** '/1c2/000+000001' // Second page in overflow chain
|
||||
** '/1c2/000+000002' // Third page in overflow chain
|
||||
**
|
||||
** If the paths are sorted using the BINARY collation sequence, then
|
||||
** the overflow pages associated with a cell will appear earlier in the
|
||||
** sort-order than its child page:
|
||||
**
|
||||
** '/1c2/000/' // Left-most child of 451st child of root
|
||||
*/
|
||||
#define VTAB_SCHEMA \
|
||||
"CREATE TABLE xx( " \
|
||||
" name STRING, /* Name of table or index */" \
|
||||
" path INTEGER, /* Path to page from root */" \
|
||||
" pageno INTEGER, /* Page number */" \
|
||||
" pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \
|
||||
" ncell INTEGER, /* Cells on page (0 for overflow) */" \
|
||||
" payload INTEGER, /* Bytes of payload on this page */" \
|
||||
" unused INTEGER, /* Bytes of unused space on this page */" \
|
||||
" mx_payload INTEGER /* Largest payload size of all cells */" \
|
||||
");"
|
||||
|
||||
#if 0
|
||||
#define VTAB_SCHEMA2 \
|
||||
"CREATE TABLE yy( " \
|
||||
" pageno INTEGER, /* B-tree page number */" \
|
||||
" cellno INTEGER, /* Cell number within page */" \
|
||||
" local INTEGER, /* Bytes of content stored locally */" \
|
||||
" payload INTEGER, /* Total cell payload size */" \
|
||||
" novfl INTEGER /* Number of overflow pages */" \
|
||||
");"
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct StatTable StatTable;
|
||||
typedef struct StatCursor StatCursor;
|
||||
typedef struct StatPage StatPage;
|
||||
typedef struct StatCell StatCell;
|
||||
|
||||
struct StatCell {
|
||||
int nLocal; /* Bytes of local payload */
|
||||
u32 iChildPg; /* Child node (or 0 if this is a leaf) */
|
||||
int nOvfl; /* Entries in aOvfl[] */
|
||||
u32 *aOvfl; /* Array of overflow page numbers */
|
||||
int nLastOvfl; /* Bytes of payload on final overflow page */
|
||||
int iOvfl; /* Iterates through aOvfl[] */
|
||||
};
|
||||
|
||||
struct StatPage {
|
||||
u32 iPgno;
|
||||
DbPage *pPg;
|
||||
int iCell;
|
||||
|
||||
char *zPath; /* Path to this page */
|
||||
|
||||
/* Variables populated by statDecodePage(): */
|
||||
u8 flags; /* Copy of flags byte */
|
||||
int nCell; /* Number of cells on page */
|
||||
int nUnused; /* Number of unused bytes on page */
|
||||
StatCell *aCell; /* Array of parsed cells */
|
||||
u32 iRightChildPg; /* Right-child page number (or 0) */
|
||||
int nMxPayload; /* Largest payload of any cell on this page */
|
||||
};
|
||||
|
||||
struct StatCursor {
|
||||
sqlite3_vtab_cursor base;
|
||||
sqlite3_stmt *pStmt; /* Iterates through set of root pages */
|
||||
int isEof; /* After pStmt has returned SQLITE_DONE */
|
||||
|
||||
StatPage aPage[32];
|
||||
int iPage; /* Current entry in aPage[] */
|
||||
|
||||
/* Values to return. */
|
||||
char *zName; /* Value of 'name' column */
|
||||
char *zPath; /* Value of 'path' column */
|
||||
u32 iPageno; /* Value of 'pageno' column */
|
||||
char *zPagetype; /* Value of 'pagetype' column */
|
||||
int nCell; /* Value of 'ncell' column */
|
||||
int nPayload; /* Value of 'payload' column */
|
||||
int nUnused; /* Value of 'unused' column */
|
||||
int nMxPayload; /* Value of 'mx_payload' column */
|
||||
};
|
||||
|
||||
struct StatTable {
|
||||
sqlite3_vtab base;
|
||||
sqlite3 *db;
|
||||
};
|
||||
|
||||
#ifndef get2byte
|
||||
# define get2byte(x) ((x)[0]<<8 | (x)[1])
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Connect to or create a statvfs virtual table.
|
||||
*/
|
||||
static int statConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
StatTable *pTab;
|
||||
|
||||
pTab = (StatTable *)sqlite3_malloc(sizeof(StatTable));
|
||||
memset(pTab, 0, sizeof(StatTable));
|
||||
pTab->db = db;
|
||||
|
||||
sqlite3_declare_vtab(db, VTAB_SCHEMA);
|
||||
*ppVtab = &pTab->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Disconnect from or destroy a statvfs virtual table.
|
||||
*/
|
||||
static int statDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** There is no "best-index". This virtual table always does a linear
|
||||
** scan of the binary VFS log file.
|
||||
*/
|
||||
static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
|
||||
/* Records are always returned in ascending order of (name, path).
|
||||
** If this will satisfy the client, set the orderByConsumed flag so that
|
||||
** SQLite does not do an external sort.
|
||||
*/
|
||||
if( ( pIdxInfo->nOrderBy==1
|
||||
&& pIdxInfo->aOrderBy[0].iColumn==0
|
||||
&& pIdxInfo->aOrderBy[0].desc==0
|
||||
) ||
|
||||
( pIdxInfo->nOrderBy==2
|
||||
&& pIdxInfo->aOrderBy[0].iColumn==0
|
||||
&& pIdxInfo->aOrderBy[0].desc==0
|
||||
&& pIdxInfo->aOrderBy[1].iColumn==1
|
||||
&& pIdxInfo->aOrderBy[1].desc==0
|
||||
)
|
||||
){
|
||||
pIdxInfo->orderByConsumed = 1;
|
||||
}
|
||||
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new statvfs cursor.
|
||||
*/
|
||||
static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
StatTable *pTab = (StatTable *)pVTab;
|
||||
StatCursor *pCsr;
|
||||
int rc;
|
||||
|
||||
pCsr = (StatCursor *)sqlite3_malloc(sizeof(StatCursor));
|
||||
memset(pCsr, 0, sizeof(StatCursor));
|
||||
pCsr->base.pVtab = pVTab;
|
||||
|
||||
rc = sqlite3_prepare_v2(pTab->db,
|
||||
"SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
|
||||
" UNION ALL "
|
||||
"SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0"
|
||||
" ORDER BY name", -1,
|
||||
&pCsr->pStmt, 0
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(pCsr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static void statClearPage(StatPage *p){
|
||||
int i;
|
||||
for(i=0; i<p->nCell; i++){
|
||||
sqlite3_free(p->aCell[i].aOvfl);
|
||||
}
|
||||
sqlite3PagerUnref(p->pPg);
|
||||
sqlite3_free(p->aCell);
|
||||
sqlite3_free(p->zPath);
|
||||
memset(p, 0, sizeof(StatPage));
|
||||
}
|
||||
|
||||
static void statResetCsr(StatCursor *pCsr){
|
||||
int i;
|
||||
sqlite3_reset(pCsr->pStmt);
|
||||
for(i=0; i<ArraySize(pCsr->aPage); i++){
|
||||
statClearPage(&pCsr->aPage[i]);
|
||||
}
|
||||
pCsr->iPage = 0;
|
||||
sqlite3_free(pCsr->zPath);
|
||||
pCsr->zPath = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a statvfs cursor.
|
||||
*/
|
||||
static int statClose(sqlite3_vtab_cursor *pCursor){
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
statResetCsr(pCsr);
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
sqlite3_free(pCsr);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static void getLocalPayload(
|
||||
int nUsable, /* Usable bytes per page */
|
||||
u8 flags, /* Page flags */
|
||||
int nTotal, /* Total record (payload) size */
|
||||
int *pnLocal /* OUT: Bytes stored locally */
|
||||
){
|
||||
int nLocal;
|
||||
int nMinLocal;
|
||||
int nMaxLocal;
|
||||
|
||||
if( flags==0x0D ){ /* Table leaf node */
|
||||
nMinLocal = (nUsable - 12) * 32 / 255 - 23;
|
||||
nMaxLocal = nUsable - 35;
|
||||
}else{ /* Index interior and leaf nodes */
|
||||
nMinLocal = (nUsable - 12) * 32 / 255 - 23;
|
||||
nMaxLocal = (nUsable - 12) * 64 / 255 - 23;
|
||||
}
|
||||
|
||||
nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
|
||||
if( nLocal>nMaxLocal ) nLocal = nMinLocal;
|
||||
*pnLocal = nLocal;
|
||||
}
|
||||
|
||||
static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
int nUnused;
|
||||
int iOff;
|
||||
int nHdr;
|
||||
int isLeaf;
|
||||
|
||||
u8 *aData = sqlite3PagerGetData(p->pPg);
|
||||
u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
|
||||
|
||||
p->flags = aHdr[0];
|
||||
p->nCell = get2byte(&aHdr[3]);
|
||||
p->nMxPayload = 0;
|
||||
|
||||
isLeaf = (p->flags==0x0A || p->flags==0x0D);
|
||||
nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
|
||||
|
||||
nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
|
||||
nUnused += (int)aHdr[7];
|
||||
iOff = get2byte(&aHdr[1]);
|
||||
while( iOff ){
|
||||
nUnused += get2byte(&aData[iOff+2]);
|
||||
iOff = get2byte(&aData[iOff]);
|
||||
}
|
||||
p->nUnused = nUnused;
|
||||
p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
|
||||
|
||||
if( p->nCell ){
|
||||
int i; /* Used to iterate through cells */
|
||||
int nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt);
|
||||
|
||||
p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell));
|
||||
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
|
||||
|
||||
for(i=0; i<p->nCell; i++){
|
||||
StatCell *pCell = &p->aCell[i];
|
||||
|
||||
iOff = get2byte(&aData[nHdr+i*2]);
|
||||
if( !isLeaf ){
|
||||
pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
|
||||
iOff += 4;
|
||||
}
|
||||
if( p->flags==0x05 ){
|
||||
/* A table interior node. nPayload==0. */
|
||||
}else{
|
||||
u32 nPayload; /* Bytes of payload total (local+overflow) */
|
||||
int nLocal; /* Bytes of payload stored locally */
|
||||
iOff += getVarint32(&aData[iOff], nPayload);
|
||||
if( p->flags==0x0D ){
|
||||
u64 dummy;
|
||||
iOff += sqlite3GetVarint(&aData[iOff], &dummy);
|
||||
}
|
||||
if( nPayload>p->nMxPayload ) p->nMxPayload = nPayload;
|
||||
getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
|
||||
pCell->nLocal = nLocal;
|
||||
assert( nPayload>=nLocal );
|
||||
assert( nLocal<=(nUsable-35) );
|
||||
if( nPayload>nLocal ){
|
||||
int j;
|
||||
int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
|
||||
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
|
||||
pCell->nOvfl = nOvfl;
|
||||
pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl);
|
||||
pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
|
||||
for(j=1; j<nOvfl; j++){
|
||||
int rc;
|
||||
u32 iPrev = pCell->aOvfl[j-1];
|
||||
DbPage *pPg = 0;
|
||||
rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( pPg==0 );
|
||||
return rc;
|
||||
}
|
||||
pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
|
||||
sqlite3PagerUnref(pPg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move a statvfs cursor to the next entry in the file.
|
||||
*/
|
||||
static int statNext(sqlite3_vtab_cursor *pCursor){
|
||||
int rc;
|
||||
int nPayload;
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
StatTable *pTab = (StatTable *)pCursor->pVtab;
|
||||
Btree *pBt = pTab->db->aDb[0].pBt;
|
||||
Pager *pPager = sqlite3BtreePager(pBt);
|
||||
|
||||
sqlite3_free(pCsr->zPath);
|
||||
pCsr->zPath = 0;
|
||||
|
||||
if( pCsr->aPage[0].pPg==0 ){
|
||||
rc = sqlite3_step(pCsr->pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1);
|
||||
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
|
||||
pCsr->aPage[0].iPgno = iRoot;
|
||||
pCsr->aPage[0].iCell = 0;
|
||||
pCsr->aPage[0].zPath = sqlite3_mprintf("/");
|
||||
pCsr->iPage = 0;
|
||||
}else{
|
||||
pCsr->isEof = 1;
|
||||
return sqlite3_reset(pCsr->pStmt);
|
||||
}
|
||||
}else{
|
||||
|
||||
/* Page p itself has already been visited. */
|
||||
StatPage *p = &pCsr->aPage[pCsr->iPage];
|
||||
|
||||
while( p->iCell<p->nCell ){
|
||||
StatCell *pCell = &p->aCell[p->iCell];
|
||||
if( pCell->iOvfl<pCell->nOvfl ){
|
||||
int nUsable = sqlite3BtreeGetPageSize(pBt)-sqlite3BtreeGetReserve(pBt);
|
||||
pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
|
||||
pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
|
||||
pCsr->zPagetype = "overflow";
|
||||
pCsr->nCell = 0;
|
||||
pCsr->nMxPayload = 0;
|
||||
pCsr->zPath = sqlite3_mprintf(
|
||||
"%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
|
||||
);
|
||||
if( pCell->iOvfl<pCell->nOvfl-1 ){
|
||||
pCsr->nUnused = 0;
|
||||
pCsr->nPayload = nUsable - 4;
|
||||
}else{
|
||||
pCsr->nPayload = pCell->nLastOvfl;
|
||||
pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
|
||||
}
|
||||
pCell->iOvfl++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( p->iRightChildPg ) break;
|
||||
p->iCell++;
|
||||
}
|
||||
|
||||
while( !p->iRightChildPg || p->iCell>p->nCell ){
|
||||
statClearPage(p);
|
||||
if( pCsr->iPage==0 ) return statNext(pCursor);
|
||||
pCsr->iPage--;
|
||||
p = &pCsr->aPage[pCsr->iPage];
|
||||
}
|
||||
pCsr->iPage++;
|
||||
assert( p==&pCsr->aPage[pCsr->iPage-1] );
|
||||
|
||||
if( p->iCell==p->nCell ){
|
||||
p[1].iPgno = p->iRightChildPg;
|
||||
}else{
|
||||
p[1].iPgno = p->aCell[p->iCell].iChildPg;
|
||||
}
|
||||
rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
|
||||
p[1].iCell = 0;
|
||||
p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
|
||||
p->iCell++;
|
||||
}
|
||||
|
||||
|
||||
/* Populate the StatCursor fields with the values to be returned
|
||||
** by the xColumn() and xRowid() methods.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
int i;
|
||||
StatPage *p = &pCsr->aPage[pCsr->iPage];
|
||||
pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
|
||||
pCsr->iPageno = p->iPgno;
|
||||
|
||||
statDecodePage(pBt, p);
|
||||
|
||||
switch( p->flags ){
|
||||
case 0x05: /* table internal */
|
||||
case 0x02: /* index internal */
|
||||
pCsr->zPagetype = "internal";
|
||||
break;
|
||||
case 0x0D: /* table leaf */
|
||||
case 0x0A: /* index leaf */
|
||||
pCsr->zPagetype = "leaf";
|
||||
break;
|
||||
default:
|
||||
pCsr->zPagetype = "corrupted";
|
||||
break;
|
||||
}
|
||||
pCsr->nCell = p->nCell;
|
||||
pCsr->nUnused = p->nUnused;
|
||||
pCsr->nMxPayload = p->nMxPayload;
|
||||
pCsr->zPath = sqlite3_mprintf("%s", p->zPath);
|
||||
nPayload = 0;
|
||||
for(i=0; i<p->nCell; i++){
|
||||
nPayload += p->aCell[i].nLocal;
|
||||
}
|
||||
pCsr->nPayload = nPayload;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int statEof(sqlite3_vtab_cursor *pCursor){
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
return pCsr->isEof;
|
||||
}
|
||||
|
||||
static int statFilter(
|
||||
sqlite3_vtab_cursor *pCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = ((StatTable *)(pCursor->pVtab))->db;
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
int nPage = 0;
|
||||
|
||||
statResetCsr((StatCursor *)pCursor);
|
||||
sqlite3PagerPagecount(sqlite3BtreePager(db->aDb[0].pBt), &nPage);
|
||||
if( nPage==0 ){
|
||||
pCsr->isEof = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
return statNext(pCursor);
|
||||
}
|
||||
|
||||
static int statColumn(
|
||||
sqlite3_vtab_cursor *pCursor,
|
||||
sqlite3_context *ctx,
|
||||
int i
|
||||
){
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
switch( i ){
|
||||
case 0: /* name */
|
||||
sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 1: /* path */
|
||||
sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
|
||||
break;
|
||||
case 2: /* pageno */
|
||||
sqlite3_result_int64(ctx, pCsr->iPageno);
|
||||
break;
|
||||
case 3: /* pagetype */
|
||||
sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 4: /* ncell */
|
||||
sqlite3_result_int(ctx, pCsr->nCell);
|
||||
break;
|
||||
case 5: /* payload */
|
||||
sqlite3_result_int(ctx, pCsr->nPayload);
|
||||
break;
|
||||
case 6: /* unused */
|
||||
sqlite3_result_int(ctx, pCsr->nUnused);
|
||||
break;
|
||||
case 7: /* mx_payload */
|
||||
sqlite3_result_int(ctx, pCsr->nMxPayload);
|
||||
break;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
*pRowid = pCsr->iPageno;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int sqlite3_dbstat_register(sqlite3 *db){
|
||||
static sqlite3_module dbstat_module = {
|
||||
0, /* iVersion */
|
||||
statConnect, /* xCreate */
|
||||
statConnect, /* xConnect */
|
||||
statBestIndex, /* xBestIndex */
|
||||
statDisconnect, /* xDisconnect */
|
||||
statDisconnect, /* xDestroy */
|
||||
statOpen, /* xOpen - open a cursor */
|
||||
statClose, /* xClose - close a cursor */
|
||||
statFilter, /* xFilter - configure scan constraints */
|
||||
statNext, /* xNext - advance a cursor */
|
||||
statEof, /* xEof - check for end of scan */
|
||||
statColumn, /* xColumn - read data */
|
||||
statRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
#include <tcl.h>
|
||||
|
||||
static int test_dbstat(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
Tcl_AppendResult(interp, "dbstat not available because of "
|
||||
"SQLITE_OMIT_VIRTUALTABLE", (void*)0);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
struct SqliteDb { sqlite3 *db; };
|
||||
char *zDb;
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
zDb = Tcl_GetString(objv[1]);
|
||||
if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
|
||||
sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
|
||||
sqlite3_dbstat_register(db);
|
||||
}
|
||||
return TCL_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SqlitetestStat_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
@ -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);
|
||||
@ -148,6 +150,8 @@ static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
|
||||
Tcl_DecrRefCount(pList);
|
||||
Tcl_DecrRefCount(pRes);
|
||||
Tcl_DeleteInterp(interp);
|
||||
while( Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT) );
|
||||
Tcl_ExitThread(0);
|
||||
TCL_THREAD_CREATE_RETURN;
|
||||
}
|
||||
|
||||
|
1408
src/test_vfs.c
Normal file
1408
src/test_vfs.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -496,6 +496,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
@ -826,6 +827,7 @@ static TriggerPrg *codeRowTrigger(
|
||||
pSubParse->pToplevel = pTop;
|
||||
pSubParse->zAuthContext = pTrigger->zName;
|
||||
pSubParse->eTriggerOp = pTrigger->op;
|
||||
pSubParse->nQueryLoop = pParse->nQueryLoop;
|
||||
|
||||
v = sqlite3GetVdbe(pSubParse);
|
||||
if( v ){
|
||||
|
@ -8,7 +8,7 @@
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
sqlite*************************************************************************
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
*/
|
||||
@ -212,6 +212,7 @@ void sqlite3Update(
|
||||
pRowidExpr = pChanges->a[i].pExpr;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
|
||||
pParse->checkSchema = 1;
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
@ -396,8 +397,7 @@ void sqlite3Update(
|
||||
);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);
|
||||
sqlite3ColumnDefault(v, pTab, i, regOld+i);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
|
||||
}
|
||||
|
19
src/vacuum.c
19
src/vacuum.c
@ -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( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
|
||||
==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
|
||||
|
238
src/vdbe.c
238
src/vdbe.c
@ -480,22 +480,6 @@ static void registerTrace(FILE *out, int iReg, Mem *p){
|
||||
#define CHECK_FOR_INTERRUPT \
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int fileExists(sqlite3 *db, const char *zFile){
|
||||
int res = 0;
|
||||
int rc = SQLITE_OK;
|
||||
#ifdef SQLITE_TEST
|
||||
/* If we are currently testing IO errors, then do not call OsAccess() to
|
||||
** test for the presence of zFile. This is because any IO error that
|
||||
** occurs here will not be reported, causing the test to fail.
|
||||
*/
|
||||
extern int sqlite3_io_error_pending;
|
||||
if( sqlite3_io_error_pending<=0 )
|
||||
#endif
|
||||
rc = sqlite3OsAccess(db->pVfs, zFile, SQLITE_ACCESS_EXISTS, &res);
|
||||
return (res && rc==SQLITE_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
@ -594,9 +578,7 @@ int sqlite3VdbeExec(
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
sqlite3BeginBenignMalloc();
|
||||
if( p->pc==0
|
||||
&& ((p->db->flags & SQLITE_VdbeListing) || fileExists(db, "vdbe_explain"))
|
||||
){
|
||||
if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
|
||||
int i;
|
||||
printf("VDBE Program Listing:\n");
|
||||
sqlite3VdbePrintSql(p);
|
||||
@ -604,9 +586,6 @@ int sqlite3VdbeExec(
|
||||
sqlite3VdbePrintOp(stdout, i, &aOp[i]);
|
||||
}
|
||||
}
|
||||
if( fileExists(db, "vdbe_trace") ){
|
||||
p->trace = stdout;
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
#endif
|
||||
for(pc=p->pc; rc==SQLITE_OK; pc++){
|
||||
@ -628,13 +607,6 @@ int sqlite3VdbeExec(
|
||||
}
|
||||
sqlite3VdbePrintOp(p->trace, pc, pOp);
|
||||
}
|
||||
if( p->trace==0 && pc==0 ){
|
||||
sqlite3BeginBenignMalloc();
|
||||
if( fileExists(db, "vdbe_sqltrace") ){
|
||||
sqlite3VdbePrintSql(p);
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -989,38 +961,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 +1340,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 +3025,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 +3039,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 =
|
||||
@ -4173,14 +4138,13 @@ case OP_Rewind: { /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
res = 1;
|
||||
if( (pCrsr = pC->pCursor)!=0 ){
|
||||
rc = sqlite3BtreeFirst(pCrsr, &res);
|
||||
pC->atFirst = res==0 ?1:0;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->rowidIsValid = 0;
|
||||
}else{
|
||||
res = 1;
|
||||
}
|
||||
pC->nullRow = (u8)res;
|
||||
assert( pOp->p2>0 && pOp->p2<p->nOp );
|
||||
@ -4190,7 +4154,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 +4163,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 +4176,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 +4188,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 +5142,139 @@ 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
|
||||
|
||||
#ifndef SQLITE_OMIT_PRAGMA
|
||||
/* 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.
|
||||
*/
|
||||
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 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);
|
||||
eOld = sqlite3PagerGetJournalMode(pPager);
|
||||
if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld;
|
||||
if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld;
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
zFilename = sqlite3PagerFilename(pPager);
|
||||
|
||||
/* Do not allow a transition to journal_mode=WAL for a database
|
||||
** in temporary storage or if the VFS does not support shared memory
|
||||
*/
|
||||
if( eNew==PAGER_JOURNALMODE_WAL
|
||||
&& (zFilename[0]==0 /* Temp file */
|
||||
|| !sqlite3PagerWalSupported(pPager)) /* No shared-memory support */
|
||||
){
|
||||
eNew = eOld;
|
||||
}
|
||||
|
||||
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 ){
|
||||
sqlite3PagerSetJournalMode(pPager, eNew);
|
||||
}
|
||||
}else if( eOld==PAGER_JOURNALMODE_MEMORY ){
|
||||
/* Cannot transition directly from MEMORY to WAL. Use mode OFF
|
||||
** as an intermediate */
|
||||
sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
||||
|
||||
if( rc ){
|
||||
eNew = eOld;
|
||||
}
|
||||
eNew = sqlite3PagerSetJournalMode(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;
|
||||
};
|
||||
#endif /* SQLITE_OMIT_PRAGMA */
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/* Opcode: Vacuum * * * * *
|
||||
@ -5616,19 +5720,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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
@ -814,9 +814,12 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
||||
**
|
||||
** If a memory allocation error has occurred prior to the calling of this
|
||||
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
|
||||
** is readable and writable, but it has no effect. The return of a dummy
|
||||
** opcode allows the call to continue functioning after a OOM fault without
|
||||
** having to check to see if the return from this routine is a valid pointer.
|
||||
** is readable but not writable, though it is cast to a writable value.
|
||||
** The return of a dummy opcode allows the call to continue functioning
|
||||
** after a OOM fault without having to check to see if the return from
|
||||
** this routine is a valid pointer. But because the dummy.opcode is 0,
|
||||
** dummy will never be written to. This is verified by code inspection and
|
||||
** by running with Valgrind.
|
||||
**
|
||||
** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
|
||||
** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
|
||||
@ -827,17 +830,19 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
||||
** check the value of p->nOp-1 before continuing.
|
||||
*/
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
||||
static VdbeOp dummy;
|
||||
/* C89 specifies that the constant "dummy" will be initialized to all
|
||||
** zeros, which is correct. MSVC generates a warning, nevertheless. */
|
||||
static const VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( addr<0 ){
|
||||
#ifdef SQLITE_OMIT_TRACE
|
||||
if( p->nOp==0 ) return &dummy;
|
||||
if( p->nOp==0 ) return (VdbeOp*)&dummy;
|
||||
#endif
|
||||
addr = p->nOp - 1;
|
||||
}
|
||||
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
|
||||
if( p->db->mallocFailed ){
|
||||
return &dummy;
|
||||
return (VdbeOp*)&dummy;
|
||||
}else{
|
||||
return &p->aOp[addr];
|
||||
}
|
||||
@ -950,6 +955,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 +1459,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->cacheCtr = 1;
|
||||
p->minWriteFileFormat = 255;
|
||||
p->iStatement = 0;
|
||||
p->nFkConstraint = 0;
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
int i;
|
||||
@ -2137,10 +2148,17 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
*/
|
||||
if( eStatementOp ){
|
||||
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
|
||||
if( rc && (NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT) ){
|
||||
p->rc = rc;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
if( rc ){
|
||||
assert( eStatementOp==SAVEPOINT_ROLLBACK );
|
||||
if( NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT ){
|
||||
p->rc = rc;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
}
|
||||
invalidateCursorsOnModifiedBtrees(db);
|
||||
sqlite3RollbackAll(db);
|
||||
sqlite3CloseSavepoints(db);
|
||||
db->autoCommit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,10 +191,14 @@ int sqlite3_blob_open(
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
|
||||
/* Configure the OP_TableLock instruction */
|
||||
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||
sqlite3VdbeChangeToNoop(v, 2, 1);
|
||||
#else
|
||||
sqlite3VdbeChangeP1(v, 2, iDb);
|
||||
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2, flags);
|
||||
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
|
||||
#endif
|
||||
|
||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||
** parameter of the other to pTab->tnum. */
|
||||
|
@ -1015,9 +1015,16 @@ int sqlite3ValueFromExpr(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
op = pExpr->op;
|
||||
if( op==TK_REGISTER ){
|
||||
op = pExpr->op2; /* This only happens with SQLITE_ENABLE_STAT2 */
|
||||
}
|
||||
|
||||
/* op can only be TK_REGISTER is we have compiled with SQLITE_ENABLE_STAT2.
|
||||
** The ifdef here is to enable us to achieve 100% branch test coverage even
|
||||
** when SQLITE_ENABLE_STAT2 is omitted.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#else
|
||||
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
||||
#endif
|
||||
|
||||
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
|
||||
pVal = sqlite3ValueNew(db);
|
||||
|
@ -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
|
||||
|
107
src/wal.h
Normal file
107
src/wal.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
** 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 sqlite3WalBeginReadTransaction(y,z) 0
|
||||
# define sqlite3WalEndReadTransaction(z)
|
||||
# define sqlite3WalRead(v,w,x,y,z) 0
|
||||
# define sqlite3WalDbsize(y,z)
|
||||
# define sqlite3WalBeginWriteTransaction(y) 0
|
||||
# define sqlite3WalEndWriteTransaction(x) 0
|
||||
# define sqlite3WalUndo(x,y,z) 0
|
||||
# define sqlite3WalSavepoint(y,z)
|
||||
# define sqlite3WalSavepointUndo(y,z) 0
|
||||
# define sqlite3WalFrames(u,v,w,x,y,z) 0
|
||||
# define sqlite3WalCheckpoint(u,v,w,x) 0
|
||||
# define sqlite3WalCallback(z) 0
|
||||
# define sqlite3WalExclusiveMode(y,z) 0
|
||||
#else
|
||||
|
||||
#define WAL_SAVEPOINT_NDATA 4
|
||||
|
||||
/* 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 sqlite3WalBeginReadTransaction(Wal *pWal, int *);
|
||||
void sqlite3WalEndReadTransaction(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 sqlite3WalBeginWriteTransaction(Wal *pWal);
|
||||
int sqlite3WalEndWriteTransaction(Wal *pWal);
|
||||
|
||||
/* Undo any frames written (but not committed) to the log */
|
||||
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
|
||||
|
||||
/* Return an integer that records the current (uncommitted) write
|
||||
** position in the WAL */
|
||||
void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
|
||||
|
||||
/* Move the write position of the WAL back to iFrame. Called in
|
||||
** response to a ROLLBACK TO command. */
|
||||
int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
|
||||
|
||||
/* 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 */
|
||||
);
|
||||
|
||||
/* 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_ */
|
493
src/where.c
493
src/where.c
@ -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( (u32)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;
|
||||
@ -2362,7 +2622,7 @@ static void bestBtreeIndex(
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
nInMul *= 25;
|
||||
bInEst = 1;
|
||||
}else if( pExpr->x.pList ){
|
||||
}else if( ALWAYS(pExpr->x.pList) ){
|
||||
nInMul *= pExpr->x.pList->nExpr + 1;
|
||||
}
|
||||
}else if( pTerm->eOperator & WO_ISNULL ){
|
||||
@ -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);
|
||||
@ -3057,7 +3384,8 @@ static Bitmask codeOneLoopStart(
|
||||
int iIdxCur; /* The VDBE cursor for the index */
|
||||
int nExtraReg = 0; /* Number of extra registers needed */
|
||||
int op; /* Instruction opcode */
|
||||
char *zAff;
|
||||
char *zStartAff; /* Affinity for start of range constraint */
|
||||
char *zEndAff; /* Affinity for end of range constraint */
|
||||
|
||||
pIdx = pLevel->plan.u.pIdx;
|
||||
iIdxCur = pLevel->iIdxCur;
|
||||
@ -3098,15 +3426,16 @@ static Bitmask codeOneLoopStart(
|
||||
** starting at regBase.
|
||||
*/
|
||||
regBase = codeAllEqualityTerms(
|
||||
pParse, pLevel, pWC, notReady, nExtraReg, &zAff
|
||||
pParse, pLevel, pWC, notReady, nExtraReg, &zStartAff
|
||||
);
|
||||
zEndAff = sqlite3DbStrDup(pParse->db, zStartAff);
|
||||
addrNxt = pLevel->addrNxt;
|
||||
|
||||
/* If we are doing a reverse order scan on an ascending index, or
|
||||
** a forward order scan on a descending index, interchange the
|
||||
** start and end terms (pRangeStart and pRangeEnd).
|
||||
*/
|
||||
if( bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
|
||||
if( nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
|
||||
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
|
||||
}
|
||||
|
||||
@ -3124,15 +3453,15 @@ static Bitmask codeOneLoopStart(
|
||||
Expr *pRight = pRangeStart->pExpr->pRight;
|
||||
sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
||||
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
|
||||
if( zAff ){
|
||||
if( sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE){
|
||||
if( zStartAff ){
|
||||
if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){
|
||||
/* Since the comparison is to be performed with no conversions
|
||||
** applied to the operands, set the affinity to apply to pRight to
|
||||
** SQLITE_AFF_NONE. */
|
||||
zAff[nConstraint] = SQLITE_AFF_NONE;
|
||||
zStartAff[nEq] = SQLITE_AFF_NONE;
|
||||
}
|
||||
if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[nConstraint]) ){
|
||||
zAff[nConstraint] = SQLITE_AFF_NONE;
|
||||
if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
|
||||
zStartAff[nEq] = SQLITE_AFF_NONE;
|
||||
}
|
||||
}
|
||||
nConstraint++;
|
||||
@ -3142,7 +3471,7 @@ static Bitmask codeOneLoopStart(
|
||||
startEq = 0;
|
||||
start_constraints = 1;
|
||||
}
|
||||
codeApplyAffinity(pParse, regBase, nConstraint, zAff);
|
||||
codeApplyAffinity(pParse, regBase, nConstraint, zStartAff);
|
||||
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
|
||||
assert( op!=0 );
|
||||
testcase( op==OP_Rewind );
|
||||
@ -3162,21 +3491,22 @@ static Bitmask codeOneLoopStart(
|
||||
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
|
||||
sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
||||
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
|
||||
if( zAff ){
|
||||
if( sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE){
|
||||
if( zEndAff ){
|
||||
if( sqlite3CompareAffinity(pRight, zEndAff[nEq])==SQLITE_AFF_NONE){
|
||||
/* Since the comparison is to be performed with no conversions
|
||||
** applied to the operands, set the affinity to apply to pRight to
|
||||
** SQLITE_AFF_NONE. */
|
||||
zAff[nConstraint] = SQLITE_AFF_NONE;
|
||||
zEndAff[nEq] = SQLITE_AFF_NONE;
|
||||
}
|
||||
if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[nConstraint]) ){
|
||||
zAff[nConstraint] = SQLITE_AFF_NONE;
|
||||
if( sqlite3ExprNeedsNoAffinityChange(pRight, zEndAff[nEq]) ){
|
||||
zEndAff[nEq] = SQLITE_AFF_NONE;
|
||||
}
|
||||
}
|
||||
codeApplyAffinity(pParse, regBase, nEq+1, zAff);
|
||||
codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
|
||||
nConstraint++;
|
||||
}
|
||||
sqlite3DbFree(pParse->db, zAff);
|
||||
sqlite3DbFree(pParse->db, zStartAff);
|
||||
sqlite3DbFree(pParse->db, zEndAff);
|
||||
|
||||
/* Top of the loop body */
|
||||
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||
@ -3446,7 +3776,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 +3787,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 +3913,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 +3941,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sizeof(WhereMaskSet)
|
||||
);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
pWInfo = 0;
|
||||
goto whereBeginError;
|
||||
}
|
||||
pWInfo->nLevel = nTabList;
|
||||
@ -3611,6 +3951,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 +4053,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 +4089,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 +4103,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( j==iFrom ) iFrom++;
|
||||
continue;
|
||||
}
|
||||
mask = (isOptimal ? m : notReady);
|
||||
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
|
||||
|
||||
assert( pTabItem->pTab );
|
||||
@ -3773,8 +4119,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 +4139,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 +4195,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 +4208,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 +4233,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 +4249,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 +4262,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 +4278,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 +4349,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 +4422,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 +4478,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
|
||||
/* Final cleanup
|
||||
*/
|
||||
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
||||
whereInfoFree(db, pWInfo);
|
||||
return;
|
||||
}
|
||||
|
147
test/all.test
147
test/all.test
@ -10,135 +10,40 @@
|
||||
#***********************************************************************
|
||||
# This file runs all tests.
|
||||
#
|
||||
# $Id: all.test,v 1.62 2009/01/06 18:43:51 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
rename finish_test really_finish_test
|
||||
proc finish_test {} {
|
||||
catch {db close}
|
||||
show_memstats
|
||||
}
|
||||
|
||||
if {[file exists ./sqlite_test_count]} {
|
||||
set COUNT [exec cat ./sqlite_test_count]
|
||||
} else {
|
||||
set COUNT 1
|
||||
}
|
||||
|
||||
if {[llength $argv]>0} {
|
||||
foreach {name value} $argv {
|
||||
switch -- $name {
|
||||
-count {
|
||||
set COUNT $value
|
||||
}
|
||||
-quick {
|
||||
set ISQUICK $value
|
||||
}
|
||||
-soak {
|
||||
set SOAKTEST $value
|
||||
}
|
||||
default {
|
||||
puts stderr "Unknown option: $name"
|
||||
exit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
set argv {}
|
||||
|
||||
# LeakList will hold a list of the number of unfreed mallocs after
|
||||
# each round of the test. This number should be constant. If it
|
||||
# grows, it may mean there is a memory leak in the library.
|
||||
#
|
||||
set LeakList {}
|
||||
|
||||
set EXCLUDE {}
|
||||
lappend EXCLUDE all.test ;# This file
|
||||
lappend EXCLUDE async.test
|
||||
lappend EXCLUDE crash.test ;# Run seperately later.
|
||||
lappend EXCLUDE crash2.test ;# Run seperately later.
|
||||
lappend EXCLUDE quick.test ;# Alternate test driver script
|
||||
lappend EXCLUDE veryquick.test ;# Alternate test driver script
|
||||
lappend EXCLUDE malloc.test ;# Run seperately later.
|
||||
lappend EXCLUDE misuse.test ;# Run seperately later.
|
||||
lappend EXCLUDE memleak.test ;# Alternate test driver script
|
||||
lappend EXCLUDE permutations.test ;# Run seperately later.
|
||||
lappend EXCLUDE soak.test ;# Takes a very long time (default 1 hr)
|
||||
lappend EXCLUDE fts3.test ;# Wrapper for muliple fts3*.tests
|
||||
lappend EXCLUDE mallocAll.test ;# Wrapper for running all malloc tests
|
||||
|
||||
# Files to include in the test. If this list is empty then everything
|
||||
# that is not in the EXCLUDE list is run.
|
||||
#
|
||||
set INCLUDE {
|
||||
}
|
||||
|
||||
for {set Counter 0} {$Counter<$COUNT && $nErr==0} {incr Counter} {
|
||||
foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
|
||||
set tail [file tail $testfile]
|
||||
if {[lsearch -exact $EXCLUDE $tail]>=0} continue
|
||||
if {[llength $INCLUDE]>0 && [lsearch -exact $INCLUDE $tail]<0} continue
|
||||
reset_prng_state
|
||||
source $testfile
|
||||
catch {db close}
|
||||
if {$sqlite_open_file_count>0} {
|
||||
puts "$tail did not close all files: $sqlite_open_file_count"
|
||||
incr nErr
|
||||
lappend ::failList $tail
|
||||
set sqlite_open_file_count 0
|
||||
}
|
||||
}
|
||||
if {[info exists Leak]} {
|
||||
lappend LeakList $Leak
|
||||
}
|
||||
}
|
||||
set argv all
|
||||
source $testdir/permutations.test
|
||||
set argv ""
|
||||
|
||||
# Do one last test to look for a memory leak in the library. This will
|
||||
# only work if SQLite is compiled with the -DSQLITE_DEBUG=1 flag.
|
||||
#
|
||||
if {$LeakList!=""} {
|
||||
puts -nonewline memory-leak-test...
|
||||
incr ::nTest
|
||||
foreach x $LeakList {
|
||||
if {$x!=[lindex $LeakList 0]} {
|
||||
puts " failed!"
|
||||
puts "Expected: all values to be the same"
|
||||
puts " Got: $LeakList"
|
||||
incr ::nErr
|
||||
lappend ::failList memory-leak-test
|
||||
break
|
||||
}
|
||||
}
|
||||
puts " Ok"
|
||||
}
|
||||
run_test_suite full
|
||||
|
||||
run_test_suite memsubsys1
|
||||
run_test_suite memsubsys2
|
||||
run_test_suite singlethread
|
||||
run_test_suite multithread
|
||||
run_test_suite onefile
|
||||
run_test_suite utf16
|
||||
run_test_suite exclusive
|
||||
run_test_suite persistent_journal
|
||||
run_test_suite persistent_journal_error
|
||||
run_test_suite no_journal
|
||||
run_test_suite no_journal_error
|
||||
run_test_suite autovacuum_ioerr
|
||||
run_test_suite no_mutex_try
|
||||
run_test_suite fullmutex
|
||||
run_test_suite journaltest
|
||||
run_test_suite inmemory_journal
|
||||
run_test_suite pcache0
|
||||
run_test_suite pcache10
|
||||
run_test_suite pcache50
|
||||
run_test_suite pcache90
|
||||
run_test_suite pcache100
|
||||
|
||||
# Run the crashtest only on unix and only once. If the library does not
|
||||
# always create auto-vacuum databases, also run autovacuum_crash.test.
|
||||
#
|
||||
if {$::tcl_platform(platform)=="unix"} {
|
||||
source $testdir/crash.test
|
||||
source $testdir/crash2.test
|
||||
ifcapable !default_autovacuum {
|
||||
set argv autovacuum_crash
|
||||
source $testdir/permutations.test
|
||||
set argv ""
|
||||
run_test_suite autovacuum_crash
|
||||
}
|
||||
}
|
||||
|
||||
# Run the malloc tests and the misuse test after memory leak detection.
|
||||
# Both tests leak memory. Currently, misuse.test also leaks a handful of
|
||||
# file descriptors. This is not considered a problem, but can cause tests
|
||||
# in malloc.test to fail. So set the open-file count to zero before running
|
||||
# malloc.test to get around this.
|
||||
#
|
||||
catch {source $testdir/misuse.test}
|
||||
set sqlite_open_file_count 0
|
||||
catch {source $testdir/malloc.test}
|
||||
finish_test
|
||||
|
||||
|
||||
catch {db close}
|
||||
set sqlite_open_file_count 0
|
||||
really_finish_test
|
||||
|
@ -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}
|
||||
|
||||
|
@ -22,9 +22,15 @@ source $testdir/tester.tcl
|
||||
# We have to have pragmas in order to do this test
|
||||
ifcapable {!pragma} return
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts. See proc [set_file_format].
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests do not work if there is a codec.
|
||||
#
|
||||
#if {[catch {sqlite3 -has_codec} r] || $r} return
|
||||
#
|
||||
|
||||
# The file format change affects the way row-records stored in tables (but
|
||||
# not indices) are interpreted. Before version 3.1.3, a row-record for a
|
||||
@ -72,6 +78,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.
|
||||
#
|
||||
@ -233,7 +254,8 @@ ifcapable trigger {
|
||||
do_test alter2-4.1 {
|
||||
db close
|
||||
set_file_format 5
|
||||
sqlite3 db test.db
|
||||
catch { sqlite3 db test.db }
|
||||
set {} {}
|
||||
} {}
|
||||
do_test alter2-4.2 {
|
||||
# We have to run two queries here because the Tcl interface uses
|
||||
|
@ -296,7 +296,7 @@ do_test analyze-99.1 {
|
||||
UPDATE sqlite_master SET sql='nonsense' WHERE name='sqlite_stat1';
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catch { sqlite3 db test.db }
|
||||
catchsql {
|
||||
ANALYZE
|
||||
}
|
||||
|
@ -22,6 +22,11 @@ ifcapable !stat2 {
|
||||
return
|
||||
}
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test organization:
|
||||
#
|
||||
|
@ -23,8 +23,8 @@ proc finish_test {} {
|
||||
catch {db2 close}
|
||||
catch {db3 close}
|
||||
}
|
||||
if {[info exists ISQUICK]} { set ASYNC_SAVE_ISQUICK $ISQUICK }
|
||||
set ISQUICK 1
|
||||
if {[info exists G(isquick)]} { set ASYNC_SAVE_ISQUICK $G(isquick) }
|
||||
set G(isquick) 1
|
||||
|
||||
set ASYNC_INCLUDE {
|
||||
insert.test
|
||||
@ -43,13 +43,22 @@ set ASYNC_INCLUDE {
|
||||
# Enable asynchronous IO.
|
||||
sqlite3async_initialize "" 1
|
||||
|
||||
# This proc flushes the contents of the async-IO queue through to the
|
||||
# underlying VFS. A couple of the test scripts identified in $ASYNC_INCLUDE
|
||||
# above contain lines like "catch flush_async_queue" in places where
|
||||
# this is required for the tests to work in async mode.
|
||||
#
|
||||
proc flush_async_queue {} {
|
||||
sqlite3async_control halt idle
|
||||
sqlite3async_start
|
||||
sqlite3async_wait
|
||||
sqlite3async_control halt never
|
||||
}
|
||||
|
||||
rename do_test async_really_do_test
|
||||
proc do_test {name args} {
|
||||
uplevel async_really_do_test async_io-$name $args
|
||||
sqlite3async_start
|
||||
sqlite3async_control halt idle
|
||||
sqlite3async_wait
|
||||
sqlite3async_control halt never
|
||||
flush_async_queue
|
||||
}
|
||||
|
||||
foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
|
||||
@ -62,19 +71,13 @@ foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
|
||||
# [file delete]). If the asynchronous backend still has the file
|
||||
# open, it will become confused.
|
||||
#
|
||||
sqlite3async_control halt idle
|
||||
sqlite3async_start
|
||||
sqlite3async_wait
|
||||
sqlite3async_control halt never
|
||||
flush_async_queue
|
||||
}
|
||||
|
||||
# Flush the write-queue and disable asynchronous IO. This should ensure
|
||||
# all allocated memory is cleaned up.
|
||||
set sqlite3async_trace 1
|
||||
sqlite3async_control halt idle
|
||||
sqlite3async_start
|
||||
sqlite3async_wait
|
||||
sqlite3async_control halt never
|
||||
flush_async_queue
|
||||
sqlite3async_shutdown
|
||||
set sqlite3async_trace 0
|
||||
|
||||
@ -83,5 +86,5 @@ rename async_really_do_test do_test
|
||||
rename finish_test {}
|
||||
rename async_really_finish_test finish_test
|
||||
|
||||
if {[info exists ASYNC_SAVE_ISQUICK]} { set ISQUICK $ASYNC_SAVE_ISQUICK }
|
||||
if {[info exists ASYNC_SAVE_ISQUICK]} { set G(isquick) $ASYNC_SAVE_ISQUICK }
|
||||
finish_test
|
||||
|
@ -14,6 +14,11 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests only work for Tcl version 8.5 and later on Windows (for now)
|
||||
#
|
||||
if {$tcl_platform(platform)=="windows"} {
|
||||
@ -94,6 +99,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}}
|
||||
|
139
test/autoindex1.test
Normal file
139
test/autoindex1.test
Normal file
@ -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
|
@ -654,12 +654,14 @@ do_test autovacuum-8.1 {
|
||||
sqlite3 db2 test.db
|
||||
db eval {PRAGMA auto_vacuum}
|
||||
} {1}
|
||||
do_test autovacuum-8.2 {
|
||||
db eval {BEGIN EXCLUSIVE}
|
||||
catchsql {PRAGMA auto_vacuum} db2
|
||||
} {1 {database is locked}}
|
||||
catch {db2 close}
|
||||
catch {db eval {COMMIT}}
|
||||
if {[permutation] == ""} {
|
||||
do_test autovacuum-8.2 {
|
||||
db eval {BEGIN EXCLUSIVE}
|
||||
catchsql {PRAGMA auto_vacuum} db2
|
||||
} {1 {database is locked}}
|
||||
catch {db2 close}
|
||||
catch {db eval {COMMIT}}
|
||||
}
|
||||
|
||||
do_test autovacuum-9.1 {
|
||||
execsql {
|
||||
|
@ -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
|
||||
#
|
||||
@ -162,7 +165,7 @@ do_test avtrans-3.14 {
|
||||
} db} msg]
|
||||
lappend v $msg
|
||||
} {0 {1 2 3 4}}
|
||||
sqlite3_soft_heap_limit $soft_limit
|
||||
sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
|
||||
integrity_check avtrans-3.15
|
||||
|
||||
do_test avtrans-4.1 {
|
||||
@ -854,7 +857,7 @@ proc signature {} {
|
||||
# t3 a little larger, and thus takes a little longer, so doing 40 tests
|
||||
# is more than 2.0 times slower than doing 20 tests. Considerably more.
|
||||
#
|
||||
if {[info exists ISQUICK]} {
|
||||
if {[info exists G(isquick)]} {
|
||||
set limit 20
|
||||
} else {
|
||||
set limit 40
|
||||
@ -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
|
||||
|
@ -16,6 +16,8 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_not_use_codec
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Test organization:
|
||||
#
|
||||
@ -38,6 +40,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 +491,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 +910,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:
|
||||
#
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user