diff --git a/Makefile.in b/Makefile.in index 64433a27..fb159fee 100644 --- a/Makefile.in +++ b/Makefile.in @@ -189,8 +189,8 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.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.lo vtab.lo $(CRYPTOLIBOBJ) + vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ + vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo $(CRYPTOLIBOBJ) # Object files for the amalgamation. # @@ -287,6 +287,7 @@ SRC = \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbeblob.c \ $(TOP)/src/vdbemem.c \ + $(TOP)/src/vdbesort.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ @@ -530,6 +531,9 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl +sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl + $(TCLSH_CMD) $(TOP)/tool/split-sqlite3c.tcl + # Rule to build the amalgamation # sqlite3.lo: sqlite3.c @@ -757,6 +761,9 @@ vdbeblob.lo: $(TOP)/src/vdbeblob.c $(HDR) vdbemem.lo: $(TOP)/src/vdbemem.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbemem.c +vdbesort.lo: $(TOP)/src/vdbesort.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbesort.c + vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c @@ -788,7 +795,7 @@ tclsqlite3$(TEXE): tclsqlite-shell.lo libsqlite3.la # 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 + $(NAWK) -f $(TOP)/mkopcodec.awk opcodes.h >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 @@ -805,7 +812,7 @@ parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk $(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 + $(TCLSH_CMD) $(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 @@ -879,6 +886,7 @@ rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) # TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE +TESTFIXTURE_FLAGS += -DBUILD_sqlite TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la TESTFIXTURE_SRC1 = sqlite3.c @@ -898,18 +906,16 @@ soaktest: testfixture$(TEXE) sqlite3$(TEXE) test: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/veryquick.test -sqlite3_analyzer$(TEXE): $(TESTFIXTURE_SRC) $(TOP)/tool/spaceanal.tcl - sed \ - -e '/^#/d' \ - -e 's,\\,\\\\,g' \ - -e 's,",\\",g' \ - -e 's,^,",' \ - -e 's,$$,\\n",' \ - $(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) $(TLIBS) +sqlite3_analyzer.c: sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl + echo "#define TCLSH 2" > $@ + cat sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c >> $@ + echo "static const char *tclsh_main_loop(void){" >> $@ + echo "static const char *zMainloop = " >> $@ + $(NAWK) -f $(TOP)/tool/tostr.awk $(TOP)/tool/spaceanal.tcl >> $@ + echo "; return zMainloop; }" >> $@ +sqlite3_analyzer$(TEXE): sqlite3_analyzer.c + $(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS) # Standard install and cleanup targets # @@ -943,9 +949,11 @@ clean: rm -f $(PUBLISH) rm -f *.da *.bb *.bbg gmon.out rm -rf tsrc .target_source + rm -f tclsqlite3$(TEXE) rm -f testfixture$(TEXE) test.db - rm -f sqlite3.dll sqlite3.lib sqlite3.def + rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def rm -f sqlite3.c + rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c distclean: clean rm -f config.log config.status libtool Makefile sqlite3.pc diff --git a/Makefile.msc b/Makefile.msc index a6d1bf4c..f40936d9 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -11,22 +11,43 @@ TOP = . # USE_AMALGAMATION = 1 +# Set this non-0 to use the International Components for Unicode (ICU). +# +USE_ICU = 0 + +# Set this to non-0 to create and use PDBs. +# +SYMBOLS = 1 + +# Set this to one of the following values to enable various debugging +# features. Each level includes the debugging options from the previous +# levels. Currently, the recognized values for DEBUG are: +# +# 0 == NDEBUG: Disables assert() and other runtime diagnostics. +# 1 == Disables NDEBUG and all optimizations and then enables PDBs. +# 2 == SQLITE_DEBUG: Enables various diagnostics messages and code. +# 3 == SQLITE_WIN32_MALLOC_VALIDATE: Validate the Win32 native heap per call. +# 4 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. +# 5 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. +# +DEBUG = 0 + # Version numbers and release number for the SQLite being compiled. # VERSION = 3.7 -VERSION_NUMBER = 3007007 -RELEASE = 3.7.7 +VERSION_NUMBER = 3007009 +RELEASE = 3.7.9 # C Compiler and options for use in building executables that # will run on the platform that is doing the build. # -BCC = cl.exe -O2 +BCC = cl.exe # C Compile and options for use in building executables that # will run on the target platform. (BCC and TCC are usually the # same unless your are cross-compiling.) # -TCC = cl.exe -W3 -O2 -DSQLITE_OS_WIN=1 -I. -I$(TOP)\src -fp:precise +TCC = cl.exe -W3 -DSQLITE_OS_WIN=1 -I. -I$(TOP)\src -fp:precise # The mksqlite3c.tcl and mksqlite3h.tcl scripts will pull in # any extension header files by default. For non-amalgamation @@ -41,18 +62,82 @@ TCC = $(TCC) -I$(TOP)\ext\rtree # Omitting the define will cause extra debugging code to be inserted and # includes extra comments when "EXPLAIN stmt" is used. # +!IF $(DEBUG)==0 TCC = $(TCC) -DNDEBUG +!ENDIF + +!IF $(DEBUG)>1 +TCC = $(TCC) -DSQLITE_DEBUG +!ENDIF + +!IF $(DEBUG)>3 +TCC = $(TCC) -DSQLITE_DEBUG_OS_TRACE=1 +!ENDIF + +!IF $(DEBUG)>4 +TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE +!ENDIF -# The library that programs using TCL must link against. # -LIBTCL = tcl85.lib +# Prevent warnings about "insecure" runtime library functions being used. +# +TCC = $(TCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS + +# +# Use native Win32 heap instead of malloc/free? +# +# TCC = $(TCC) -DSQLITE_WIN32_MALLOC=1 + +# +# Validate the heap on every call into the native Win32 heap subsystem? +# +!IF $(DEBUG)>2 +TCC = $(TCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1 +!ENDIF + +# The locations of the Tcl header and library files. Also, the library that +# non-stubs enabled programs using Tcl must link against. These variables +# (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment +# prior to running nmake in order to match the actual installed location and +# version on this machine. +# +!if "$(TCLINCDIR)" == "" TCLINCDIR = c:\tcl\include +!endif + +!if "$(TCLLIBDIR)" == "" TCLLIBDIR = c:\tcl\lib +!endif + +!if "$(LIBTCL)" == "" +LIBTCL = tcl85.lib +!endif + +# The locations of the ICU header and library files. These variables +# (ICUINCDIR, ICULIBDIR, and LIBICU) may be overridden via the environment +# prior to running nmake in order to match the actual installed location on +# this machine. +# +!if "$(ICUINCDIR)" == "" +ICUINCDIR = c:\icu\include +!endif + +!if "$(ICULIBDIR)" == "" +ICULIBDIR = c:\icu\lib +!endif + +!if "$(LIBICU)" == "" +LIBICU = icuuc.lib icuin.lib +!endif # This is the command to use for tclsh - normally just "tclsh", but we may -# know the specific version we want to use +# know the specific version we want to use. This variable (TCLSH_CMD) may be +# overridden via the environment prior to running nmake in order to select a +# specific Tcl shell to use. # +!if "$(TCLSH_CMD)" == "" TCLSH_CMD = tclsh85 +!endif # Compiler options needed for programs that use the readline() library. # @@ -72,7 +157,9 @@ TCC = $(TCC) -DSQLITE_THREAD_OVERRIDE_LOCK=-1 # Any target libraries which libsqlite must be linked against # +!if "$(TLIBS)" == "" TLIBS = +!endif # Flags controlling use of the in memory btree implementation # @@ -103,6 +190,25 @@ TCC = $(TCC) $(OPT_FEATURE_FLAGS) # ie. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1". TCC = $(TCC) $(OPTS) +# If symbols are enabled, enable PDBs. +# If debugging is enabled, disable all optimizations and enable PDBs. +!IF $(DEBUG)>0 +TCC = $(TCC) -Od -D_DEBUG +!ELSE +TCC = $(TCC) -O2 +!ENDIF + +!IF $(DEBUG)>0 || $(SYMBOLS)!=0 +TCC = $(TCC) -Zi +!ENDIF + +# If ICU support is enabled, add the compiler options for it. +!IF $(USE_ICU)!=0 +TCC = $(TCC) -DSQLITE_ENABLE_ICU=1 +TCC = $(TCC) -I$(TOP)\ext\icu +TCC = $(TCC) -I$(ICUINCDIR) +!ENDIF + # libtool compile/link LTCOMPILE = $(TCC) -Fo$@ LTLIB = lib.exe @@ -117,8 +223,23 @@ LTLINKOPTS = /MACHINE:$(PLATFORM) LTLIBOPTS = /MACHINE:$(PLATFORM) !ENDIF +# If debugging is enabled, enable PDBs. +!IF $(DEBUG)>0 || $(SYMBOLS)!=0 +LTLINKOPTS = $(LTLINKOPTS) /DEBUG +!ENDIF + +# Start with the Tcl related linker options. +LTLIBPATHS = /LIBPATH:$(TCLLIBDIR) +LTLIBS = $(LIBTCL) + +# If ICU support is enabled, add the linker options for it. +!IF $(USE_ICU)!=0 +LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ICULIBDIR) +LTLIBS = $(LTLIBS) $(LIBICU) +!ENDIF + # nawk compatible awk. -NAWK = .\gawk.exe +NAWK = gawk.exe # You should not have to change anything below this line ############################################################################### @@ -141,8 +262,8 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.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.lo vtab.lo + vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ + vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo # Object files for the amalgamation. # @@ -241,6 +362,7 @@ SRC = \ $(TOP)\src\vdbeaux.c \ $(TOP)\src\vdbeblob.c \ $(TOP)\src\vdbemem.c \ + $(TOP)\src\vdbesort.c \ $(TOP)\src\vdbetrace.c \ $(TOP)\src\vdbeInt.h \ $(TOP)\src\vtab.c \ @@ -382,6 +504,7 @@ TESTSRC2 = \ $(TOP)\src\vdbeaux.c \ $(TOP)\src\vdbe.c \ $(TOP)\src\vdbemem.c \ + $(TOP)\src\vdbesort.c \ $(TOP)\src\vdbetrace.c \ $(TOP)\src\where.c \ parse.c \ @@ -439,18 +562,18 @@ EXTHDR = $(EXTHDR) \ # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # -all: libsqlite3.lib sqlite3.exe libtclsqlite3.lib +all: dll libsqlite3.lib sqlite3.exe libtclsqlite3.lib libsqlite3.lib: $(LIBOBJ) $(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS) libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib - $(LTLIB) $(LTLIBOPTS) /LIBPATH:$(TCLLIBDIR) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) + $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib sqlite3.h $(LTLINK) $(READLINE_FLAGS) \ $(TOP)\src\shell.c \ - /link $(LTLINKOPTS) libsqlite3.lib $(LIBREADLINE) $(TLIBS) + /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBREADLINE) $(LTLIBS) $(TLIBS) # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to @@ -463,13 +586,16 @@ sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib sqlite3.h -mkdir tsrc for %i in ($(SRC)) do copy /Y %i tsrc del /Q tsrc\sqlite.h.in tsrc\parse.y - $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl vdbe.new + $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl +sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl + $(TCLSH_CMD) $(TOP)/tool/split-sqlite3c.tcl + # Rule to build the amalgamation # sqlite3.lo: sqlite3.c @@ -692,6 +818,9 @@ vdbeblob.lo: $(TOP)\src\vdbeblob.c $(HDR) vdbemem.lo: $(TOP)\src\vdbemem.c $(HDR) $(LTCOMPILE) -c $(TOP)\src\vdbemem.c +vdbesort.lo: $(TOP)\src\vdbesort.c $(HDR) + $(LTCOMPILE) -c $(TOP)\src\vdbesort.c + vdbetrace.lo: $(TOP)\src\vdbetrace.c $(HDR) $(LTCOMPILE) -c $(TOP)\src\vdbetrace.c @@ -715,15 +844,15 @@ tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) tclsqlite3.exe: tclsqlite-shell.lo libsqlite3.lib $(LTLINK) tclsqlite-shell.lo \ - /link $(LTLINKOPTS) /LIBPATH:$(TCLLIBDIR) libsqlite3.lib $(LIBTCL) + /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LTLIBS) $(TLIBS) # Rules to build opcodes.c and opcodes.h # opcodes.c: opcodes.h $(TOP)\mkopcodec.awk - $(NAWK) "/#define OP_/ { print }" opcodes.h | sort /+45 | $(NAWK) -f $(TOP)\mkopcodec.awk >opcodes.c + $(NAWK) -f $(TOP)\mkopcodec.awk opcodes.h > opcodes.c opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\mkopcodeh.awk - type parse.h $(TOP)\src\vdbe.c | $(NAWK) -f $(TOP)\mkopcodeh.awk >opcodes.h + type 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. # @@ -734,16 +863,16 @@ parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\addopcodes.awk copy $(TOP)\src\parse.y . .\lemon.exe $(OPT_FEATURE_FLAGS) $(OPTS) parse.y move parse.h parse.h.temp - $(NAWK) -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_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP) >sqlite3.h + $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP) > sqlite3.h mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c $(BCC) -Femkkeywordhash.exe $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe - .\mkkeywordhash.exe >keywordhash.h + .\mkkeywordhash.exe > keywordhash.h @@ -826,7 +955,7 @@ testfixture.exe: $(TESTFIXTURE_SRC) $(HDR) $(LTLINK) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \ -DBUILD_sqlite -I$(TCLINCDIR) \ $(TESTFIXTURE_SRC) \ - /link $(LTLINKOPTS) /LIBPATH:$(TCLLIBDIR) $(LIBTCL) $(TLIBS) + /link $(LTLINKOPTS) $(LTLIBPATHS) $(LTLIBS) $(TLIBS) fulltest: testfixture.exe sqlite3.exe .\testfixture.exe $(TOP)\test\all.test @@ -837,28 +966,29 @@ soaktest: testfixture.exe sqlite3.exe test: testfixture.exe sqlite3.exe .\testfixture.exe $(TOP)\test\veryquick.test -spaceanal_tcl.h: $(TOP)\tool\spaceanal.tcl - $(NAWK) -f $(TOP)/tool/tostr.awk \ - $(TOP)\tool\spaceanal.tcl >spaceanal_tcl.h +sqlite3_analyzer.c: sqlite3.c $(TOP)\src\test_stat.c $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl + copy sqlite3.c + $(TOP)\src\test_stat.c + $(TOP)\src\tclsqlite.c $@ + echo static const char *tclsh_main_loop(void){ >> $@ + echo static const char *zMainloop = >> $@ + $(NAWK) -f $(TOP)\tool\tostr.awk $(TOP)\tool\spaceanal.tcl >> $@ + echo ; return zMainloop; } >> $@ -sqlite3_analyzer.exe: $(TESTFIXTURE_SRC) spaceanal_tcl.h - $(LTLINK) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 \ - -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE \ - -DBUILD_sqlite -I$(TCLINCDIR) \ - $(TESTFIXTURE_SRC) \ - /link $(LTLINKOPTS) /LIBPATH:$(TCLLIBDIR) $(LIBTCL) $(TLIBS) +sqlite3_analyzer.exe: sqlite3_analyzer.c + $(LTLINK) -DBUILD_sqlite -DTCLSH=2 -I$(TCLINCDIR) sqlite3_analyzer.c \ + /link $(LTLINKOPTS) $(LTLIBPATHS) $(LTLIBS) $(TLIBS) clean: - del /Q *.lo *.lib *.obj sqlite3.exe libsqlite3.lib + del /Q *.lo *.ilk *.lib *.obj *.pdb sqlite3.exe libsqlite3.lib del /Q sqlite3.h opcodes.c opcodes.h del /Q lemon.exe lempar.c parse.* del /Q mkkeywordhash.exe keywordhash.h -rmdir /Q/S tsrc del /Q .target_source + del /Q tclsqlite3.exe del /Q testfixture.exe testfixture.exp test.db del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def del /Q sqlite3.c - del /Q sqlite3_analyzer.exe sqlite3_analyzer.exp spaceanal_tcl.h + del /Q sqlite3_analyzer.exe sqlite3_analyzer.exp sqlite3_analyzer.c # # Windows section @@ -866,10 +996,10 @@ clean: dll: sqlite3.dll sqlite3.def: libsqlite3.lib - echo EXPORTS >sqlite3.def + echo EXPORTS > sqlite3.def dumpbin /all libsqlite3.lib \ - | $(NAWK) "/ 1 _sqlite3_/ { sub(/^.* _/,\"\");print }" \ - | sort >>sqlite3.def + | $(NAWK) "/ 1 _?sqlite3_/ { sub(/^.* _?/,\"\");print }" \ + | sort >> sqlite3.def sqlite3.dll: $(LIBOBJ) sqlite3.def - link $(LTLINKOPTS) /DLL /DEF:sqlite3.def /OUT:$@ $(LIBOBJ) + link $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:sqlite3.def /OUT:$@ $(LIBOBJ) $(LTLIBS) $(TLIBS) diff --git a/Makefile.vxworks b/Makefile.vxworks index 993e5579..8d57da72 100644 --- a/Makefile.vxworks +++ b/Makefile.vxworks @@ -517,7 +517,7 @@ tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR) # 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 + $(NAWK) -f $(TOP)/mkopcodec.awk opcodes.h >opcodes.c opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk cat parse.h $(TOP)/src/vdbe.c | \ diff --git a/VERSION b/VERSION index 9076adfe..c77a7de8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.7.7.1 +3.7.9 diff --git a/configure b/configure index b565366d..79cd72de 100755 --- a/configure +++ b/configure @@ -1,18 +1,22 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.62 for sqlite 3.7.7.1. +# Generated by GNU Autoconf 2.67 for sqlite 3.7.9. +# # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which @@ -20,23 +24,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; esac - fi - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - as_nl=' ' export as_nl @@ -44,7 +40,13 @@ export as_nl as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else @@ -55,7 +57,7 @@ else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; - case $arg in + case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; @@ -78,13 +80,6 @@ if test "${PATH_SEPARATOR+set}" != set; then } fi -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false -fi - # IFS # We need space, tab and new line, in precisely that order. Quoting is @@ -94,15 +89,15 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -case $0 in +case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done IFS=$as_save_IFS ;; @@ -114,12 +109,16 @@ if test "x$as_myself" = x; then fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } + exit 1 fi -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' @@ -131,7 +130,248 @@ export LC_ALL LANGUAGE=C export LANGUAGE -# Required to use basename. +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr @@ -145,8 +385,12 @@ else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ @@ -166,295 +410,19 @@ $as_echo X/"$0" | } s/.*/./; q'` -# CDPATH. -$as_unset CDPATH +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits -if test "x$CONFIG_SHELL" = x; then - if (eval ":") 2>/dev/null; then - as_have_required=yes -else - as_have_required=no -fi - - if test $as_have_required = yes && (eval ": -(as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=\$LINENO - as_lineno_2=\$LINENO - test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && - test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } -") 2> /dev/null; then - : -else - as_candidate_shells= - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - case $as_dir in - /*) - for as_base in sh bash ksh sh5; do - as_candidate_shells="$as_candidate_shells $as_dir/$as_base" - done;; - esac -done -IFS=$as_save_IFS - - - for as_shell in $as_candidate_shells $SHELL; do - # Try only shells that exist, to save several forks. - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { ("$as_shell") 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -_ASEOF -}; then - CONFIG_SHELL=$as_shell - as_have_required=yes - if { "$as_shell" 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -(as_func_return () { - (exit $1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = "$1" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test $exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } - -_ASEOF -}; then - break -fi - -fi - - done - - if test "x$CONFIG_SHELL" != x; then - for as_var in BASH_ENV ENV - do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - done - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} -fi - - - if test $as_have_required = no; then - echo This script requires a shell more modern than all the - echo shells that I found on your system. Please install a - echo modern shell, or manually run the script under such a - echo shell if you do have one. - { (exit 1); exit 1; } -fi - - -fi - -fi - - - -(eval "as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0") || { - echo No shell found that supports shell functions. - echo Please tell bug-autoconf@gnu.org about your system, - echo including any error possibly output before this message. - echo This can help us improve future autoconf versions. - echo Configuration will now proceed without shell functions. -} - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= @@ -471,8 +439,7 @@ test \$exitcode = 0") || { s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the @@ -482,29 +449,18 @@ test \$exitcode = 0") || { exit } - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in +case `echo -n x` in #((((( -n*) - case `echo 'x\c'` in + case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then @@ -534,7 +490,7 @@ rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false @@ -553,10 +509,10 @@ else if test -d "$1"; then test -d "$1/."; else - case $1 in + case $1 in #( -*)set "./$1";; esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' @@ -571,7 +527,6 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} @@ -720,10 +675,11 @@ fi -exec 7<&0 &1 +test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` @@ -738,14 +694,14 @@ cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.7.7.1' -PACKAGE_STRING='sqlite 3.7.7.1' +PACKAGE_VERSION='3.7.9' +PACKAGE_STRING='sqlite 3.7.9' PACKAGE_BUGREPORT='' +PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ @@ -783,121 +739,122 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL -PATH_SEPARATOR -PACKAGE_NAME -PACKAGE_TARNAME -PACKAGE_VERSION -PACKAGE_STRING -PACKAGE_BUGREPORT -exec_prefix -prefix -program_transform_name -bindir -sbindir -libexecdir -datarootdir -datadir -sysconfdir -sharedstatedir -localstatedir -includedir -oldincludedir -docdir -infodir -htmldir -dvidir -pdfdir -psdir -libdir -localedir -mandir -DEFS -ECHO_C -ECHO_N -ECHO_T -LIBS -build_alias -host_alias -target_alias -LIBTOOL -build -build_cpu -build_vendor -build_os -host -host_cpu -host_vendor -host_os -CC -CFLAGS -LDFLAGS -CPPFLAGS -ac_ct_CC -EXEEXT -OBJEXT -SED -GREP -EGREP -FGREP -LD -DUMPBIN -ac_ct_DUMPBIN -NM -LN_S -OBJDUMP -AR -STRIP -RANLIB -lt_ECHO -DSYMUTIL -NMEDIT -LIPO -OTOOL -OTOOL64 -CPP -INSTALL_PROGRAM -INSTALL_SCRIPT -INSTALL_DATA -AWK -TCLSH_CMD -TCLLIBDIR -program_prefix -VERSION -RELEASE -VERSION_NUMBER -BUILD_CC -SQLITE_THREADSAFE -XTHREADCONNECT -ALLOWRELEASE -TEMP_STORE -BUILD_EXEEXT -SQLITE_OS_UNIX -SQLITE_OS_WIN -SQLITE_OS_OS2 -TARGET_EXEEXT -TCL_VERSION -TCL_BIN_DIR -TCL_SRC_DIR -TCL_LIBS -TCL_INCLUDE_SPEC -TCL_LIB_FILE -TCL_LIB_FLAG -TCL_LIB_SPEC -TCL_STUB_LIB_FILE -TCL_STUB_LIB_FLAG -TCL_STUB_LIB_SPEC -HAVE_TCL -TARGET_READLINE_LIBS -TARGET_READLINE_INC -TARGET_HAVE_READLINE -TARGET_DEBUG -USE_AMALGAMATION -OPT_FEATURE_FLAGS -USE_GCOV -BUILD_CFLAGS +ac_subst_vars='LTLIBOBJS LIBOBJS -LTLIBOBJS' +BUILD_CFLAGS +USE_GCOV +OPT_FEATURE_FLAGS +USE_AMALGAMATION +TARGET_DEBUG +TARGET_HAVE_READLINE +TARGET_READLINE_INC +TARGET_READLINE_LIBS +HAVE_TCL +TCL_STUB_LIB_SPEC +TCL_STUB_LIB_FLAG +TCL_STUB_LIB_FILE +TCL_LIB_SPEC +TCL_LIB_FLAG +TCL_LIB_FILE +TCL_INCLUDE_SPEC +TCL_LIBS +TCL_SRC_DIR +TCL_BIN_DIR +TCL_VERSION +TARGET_EXEEXT +SQLITE_OS_OS2 +SQLITE_OS_WIN +SQLITE_OS_UNIX +BUILD_EXEEXT +TEMP_STORE +ALLOWRELEASE +XTHREADCONNECT +SQLITE_THREADSAFE +BUILD_CC +VERSION_NUMBER +RELEASE +VERSION +program_prefix +TCLLIBDIR +TCLSH_CMD +AWK +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +lt_ECHO +RANLIB +STRIP +AR +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking @@ -995,8 +952,9 @@ do fi case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. @@ -1041,8 +999,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1068,8 +1025,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1273,8 +1229,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1290,8 +1245,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1321,17 +1275,17 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) { $as_echo "$as_me: error: unrecognized option: $ac_option -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. - expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 - { (exit 1); exit 1; }; } + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1348,16 +1302,14 @@ done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - { $as_echo "$as_me: error: missing argument to $ac_option" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; - fatal) { $as_echo "$as_me: error: Unrecognized options: $ac_unrecognized_opts" >&2 - { (exit 1); exit 1; }; } ;; - *) $as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2 ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1379,8 +1331,7 @@ do [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac - { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' @@ -1394,8 +1345,8 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1410,11 +1361,9 @@ test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - { $as_echo "$as_me: error: Working directory cannot be determined" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. @@ -1453,13 +1402,11 @@ else fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 - { (exit 1); exit 1; }; } + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then @@ -1485,7 +1432,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.7.7.1 to adapt to many kinds of systems. +\`configure' configures sqlite 3.7.9 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1499,7 +1446,7 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages + -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files @@ -1550,7 +1497,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.7.7.1:";; + short | recursive ) echo "Configuration of sqlite 3.7.9:";; esac cat <<\_ACEOF @@ -1596,7 +1543,7 @@ Some influential environment variables: LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor TCLLIBDIR Where to install tcl plugin @@ -1604,6 +1551,7 @@ Some influential environment variables: Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. +Report bugs to the package provider. _ACEOF ac_status=$? fi @@ -1666,22 +1614,427 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.7.7.1 -generated by GNU Autoconf 2.62 +sqlite configure 3.7.9 +generated by GNU Autoconf 2.67 -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_type + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval "test \"\${$3+set}\"" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel 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.7.7.1, which was -generated by GNU Autoconf 2.62. Invocation command line was +It was created by sqlite $as_me 3.7.9, which was +generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ @@ -1717,8 +2070,8 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" -done + $as_echo "PATH: $as_dir" + done IFS=$as_save_IFS } >&5 @@ -1755,9 +2108,9 @@ do ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in - 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) - ac_configure_args1="$ac_configure_args1 '$ac_arg'" + as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else @@ -1773,13 +2126,13 @@ do -* ) ac_must_keep_next=true ;; esac fi - ac_configure_args="$ac_configure_args '$ac_arg'" + as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done -$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } -$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there @@ -1791,11 +2144,9 @@ trap 'exit_status=$? { echo - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( @@ -1804,13 +2155,13 @@ _ASBOX case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) $as_unset $ac_var ;; + *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done @@ -1829,11 +2180,9 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; ) echo - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo for ac_var in $ac_subst_vars do @@ -1846,11 +2195,9 @@ _ASBOX echo if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## + $as_echo "## ------------------- ## ## File substitutions. ## -## ------------------- ## -_ASBOX +## ------------------- ##" echo for ac_var in $ac_subst_files do @@ -1864,11 +2211,9 @@ _ASBOX fi if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo cat confdefs.h echo @@ -1882,46 +2227,53 @@ _ASBOX exit $exit_status ' 0 for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h +$as_echo "/* confdefs.h */" > confdefs.h + # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site @@ -1932,19 +2284,23 @@ fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue - if test -r "$ac_site_file"; then - { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special - # files actually), so we avoid doing that. - if test -f "$cache_file"; then - { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; @@ -1952,7 +2308,7 @@ $as_echo "$as_me: loading cache $cache_file" >&6;} esac fi else - { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi @@ -1967,11 +2323,11 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; @@ -1981,17 +2337,17 @@ $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac @@ -2003,41 +2359,20 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then - { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 -$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi - - - - - - - - - - - - - - - - - - - - - - - - +## -------------------- ## +## Main body of script. ## +## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -2049,15 +2384,10 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'` if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then -{ { $as_echo "$as_me:$LINENO: error: configure script is out of date: +as_fn_error $? "configure script is out of date: configure \$PACKAGE_VERSION = $PACKAGE_VERSION top level VERSION file = $sqlite_version_sanity_check -please regen with autoconf" >&5 -$as_echo "$as_me: error: configure script is out of date: - configure \$PACKAGE_VERSION = $PACKAGE_VERSION - top level VERSION file = $sqlite_version_sanity_check -please regen with autoconf" >&2;} - { (exit 1); exit 1; }; } +please regen with autoconf" "$LINENO" 5 fi # The following RCS revision string applies to configure.in @@ -2068,7 +2398,7 @@ fi # case `pwd` in *\ * | *\ *) - { $as_echo "$as_me:$LINENO: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac @@ -2108,9 +2438,7 @@ for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do fi done if test -z "$ac_aux_dir"; then - { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 -$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, @@ -2124,35 +2452,27 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 -$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 -{ $as_echo "$as_me:$LINENO: checking build system type" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } -if test "${ac_cv_build+set}" = set; then +if test "${ac_cv_build+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && - { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 -$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 -$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; -*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 -$as_echo "$as_me: error: invalid value of canonical build" >&2;} - { (exit 1); exit 1; }; };; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' @@ -2168,28 +2488,24 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:$LINENO: checking host system type" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } -if test "${ac_cv_host+set}" = set; then +if test "${ac_cv_host+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 -$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; -*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 -$as_echo "$as_me: error: invalid value of canonical host" >&2;} - { (exit 1); exit 1; }; };; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' @@ -2213,9 +2529,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2226,24 +2542,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2253,9 +2569,9 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -2266,24 +2582,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2292,12 +2608,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2310,9 +2622,9 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2323,24 +2635,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2350,9 +2662,9 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2364,18 +2676,18 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then @@ -2394,10 +2706,10 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2409,9 +2721,9 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2422,24 +2734,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2453,9 +2765,9 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -2466,24 +2778,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2496,12 +2808,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2511,55 +2819,37 @@ fi fi -test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. -$as_echo "$as_me:$LINENO: checking for C compiler version" >&5 +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -{ (ac_try="$ac_compiler --version >&5" +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compiler --version >&5") 2>&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -v >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compiler -v >&5") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -V >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compiler -V >&5") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2575,8 +2865,8 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: @@ -2592,17 +2882,17 @@ do done rm -f $ac_rmfiles -if { (ac_try="$ac_link_default" +if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -2619,7 +2909,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -2638,80 +2928,41 @@ test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi - -{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -if test -z "$ac_file"; then - $as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: C compiler cannot create executables -See \`config.log' for more details." >&2;} - { (exit 77); exit 77; }; } -fi - -ac_exeext=$ac_cv_exeext - -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 -# If not cross compiling, check that we can run a simple program. -if test "$cross_compiling" != yes; then - if { ac_try='./$ac_file' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - fi - fi -fi -{ $as_echo "$as_me:$LINENO: result: yes" >&5 +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5 ; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } -if { (ac_try="$ac_link" +if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -2726,30 +2977,83 @@ for ac_file in conftest.exe conftest conftest.*; do esac done else - { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5 ; } fi - -rm -f conftest$ac_cv_exeext -{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT -{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5 ; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then +if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2761,17 +3065,17 @@ main () } _ACEOF rm -f conftest.o conftest.obj -if { (ac_try="$ac_compile" +if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -2784,29 +3088,23 @@ else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5 ; } fi - rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then +if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2820,37 +3118,16 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_compiler_gnu=no + ac_compiler_gnu=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes @@ -2859,20 +3136,16 @@ else fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then +if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2883,35 +3156,11 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - CFLAGS="" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2922,36 +3171,12 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_compile "$LINENO"; then : - ac_c_werror_flag=$ac_save_c_werror_flag +else + ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2962,42 +3187,17 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS @@ -3014,18 +3214,14 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then +if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -3082,32 +3278,9 @@ for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then + if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done @@ -3118,17 +3291,19 @@ fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) - { $as_echo "$as_me:$LINENO: result: none needed" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) - { $as_echo "$as_me:$LINENO: result: unsupported" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac +if test "x$ac_cv_prog_cc_c89" != xno; then : +fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -3136,9 +3311,9 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } -if test "${ac_cv_path_SED+set}" = set; then +if test "${ac_cv_path_SED+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ @@ -3146,7 +3321,7 @@ else ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - $as_unset ac_script || ac_script= + { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST @@ -3155,7 +3330,7 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do + for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue @@ -3175,7 +3350,7 @@ case `"$ac_path_SED" --version 2>&1` in $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" @@ -3190,19 +3365,17 @@ esac $ac_path_SED_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable sed could be found in \$PATH" >&5 -$as_echo "$as_me: error: no acceptable sed could be found in \$PATH" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_SED" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed @@ -3220,9 +3393,9 @@ Xsed="$SED -e 1s/^X//" -{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then +if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -3233,7 +3406,7 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do + for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue @@ -3253,7 +3426,7 @@ case `"$ac_path_GREP" --version 2>&1` in $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" @@ -3268,26 +3441,24 @@ esac $ac_path_GREP_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" -{ $as_echo "$as_me:$LINENO: checking for egrep" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then +if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -3301,7 +3472,7 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do + for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue @@ -3321,7 +3492,7 @@ case `"$ac_path_EGREP" --version 2>&1` in $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" @@ -3336,12 +3507,10 @@ esac $ac_path_EGREP_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP @@ -3349,14 +3518,14 @@ fi fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" -{ $as_echo "$as_me:$LINENO: checking for fgrep" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } -if test "${ac_cv_path_FGREP+set}" = set; then +if test "${ac_cv_path_FGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 @@ -3370,7 +3539,7 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in fgrep; do + for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue @@ -3390,7 +3559,7 @@ case `"$ac_path_FGREP" --version 2>&1` in $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" @@ -3405,12 +3574,10 @@ esac $ac_path_FGREP_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -$as_echo "$as_me: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP @@ -3418,7 +3585,7 @@ fi fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_FGREP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" @@ -3444,7 +3611,7 @@ test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then +if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no @@ -3453,7 +3620,7 @@ fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) @@ -3483,13 +3650,13 @@ $as_echo_n "checking for ld used by $CC... " >&6; } ;; esac elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else - { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi -if test "${lt_cv_path_LD+set}" = set; then +if test "${lt_cv_path_LD+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then @@ -3520,18 +3687,16 @@ fi LD="$lt_cv_path_LD" if test -n "$LD"; then - { $as_echo "$as_me:$LINENO: result: $LD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi -test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 -$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} - { (exit 1); exit 1; }; } -{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if test "${lt_cv_prog_gnu_ld+set}" = set; then +if test "${lt_cv_prog_gnu_ld+set}" = set; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. @@ -3544,7 +3709,7 @@ case `$LD -v 2>&1 &5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld @@ -3556,9 +3721,9 @@ with_gnu_ld=$lt_cv_prog_gnu_ld -{ $as_echo "$as_me:$LINENO: checking for BSD- or MS-compatible name lister (nm)" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test "${lt_cv_path_NM+set}" = set; then +if test "${lt_cv_path_NM+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then @@ -3605,7 +3770,7 @@ else : ${lt_cv_path_NM=no} fi fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" @@ -3616,9 +3781,9 @@ else do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DUMPBIN+set}" = set; then +if test "${ac_cv_prog_DUMPBIN+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then @@ -3629,24 +3794,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then - { $as_echo "$as_me:$LINENO: result: $DUMPBIN" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -3660,9 +3825,9 @@ if test -z "$DUMPBIN"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then @@ -3673,24 +3838,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_DUMPBIN" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -3703,12 +3868,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN @@ -3727,44 +3888,44 @@ test -z "$NM" && NM=nm -{ $as_echo "$as_me:$LINENO: checking the name lister ($NM) interface" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } -if test "${lt_cv_nm_interface+set}" = set; then +if test "${lt_cv_nm_interface+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3737: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3898: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3740: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3901: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3743: output\"" >&5) + (eval echo "\"\$as_me:3904: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_nm_interface" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } -{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else - { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments -{ $as_echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } -if test "${lt_cv_sys_max_cmd_len+set}" = set; then +if test "${lt_cv_sys_max_cmd_len+set}" = set; then : $as_echo_n "(cached) " >&6 else i=0 @@ -3882,10 +4043,10 @@ else fi if test -n $lt_cv_sys_max_cmd_len ; then - { $as_echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else - { $as_echo "$as_me:$LINENO: result: none" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len @@ -3899,7 +4060,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len : ${MV="mv -f"} : ${RM="rm -f"} -{ $as_echo "$as_me:$LINENO: checking whether the shell understands some XSI constructs" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no @@ -3909,17 +4070,17 @@ xsi_shell=no && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes -{ $as_echo "$as_me:$LINENO: result: $xsi_shell" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } -{ $as_echo "$as_me:$LINENO: checking whether the shell understands \"+=\"" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes -{ $as_echo "$as_me:$LINENO: result: $lt_shell_append" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } @@ -3954,14 +4115,14 @@ esac -{ $as_echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } -if test "${lt_cv_ld_reload_flag+set}" = set; then +if test "${lt_cv_ld_reload_flag+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in @@ -3990,9 +4151,9 @@ esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OBJDUMP+set}" = set; then +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then @@ -4003,24 +4164,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then - { $as_echo "$as_me:$LINENO: result: $OBJDUMP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4030,9 +4191,9 @@ if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then @@ -4043,24 +4204,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJDUMP="objdump" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_OBJDUMP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4069,12 +4230,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP @@ -4093,9 +4250,9 @@ test -z "$OBJDUMP" && OBJDUMP=objdump -{ $as_echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } -if test "${lt_cv_deplibs_check_method+set}" = set; then +if test "${lt_cv_deplibs_check_method+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' @@ -4289,7 +4446,7 @@ tpf*) esac fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method @@ -4309,9 +4466,9 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then +if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -4322,24 +4479,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="${ac_tool_prefix}ar" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then - { $as_echo "$as_me:$LINENO: result: $AR" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4349,9 +4506,9 @@ if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_AR+set}" = set; then +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then @@ -4362,24 +4519,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="ar" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4388,12 +4545,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR @@ -4418,9 +4571,9 @@ test -z "$AR_FLAGS" && AR_FLAGS=cru if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then +if test "${ac_cv_prog_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then @@ -4431,24 +4584,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then - { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4458,9 +4611,9 @@ if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then @@ -4471,24 +4624,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4497,12 +4650,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP @@ -4521,9 +4670,9 @@ test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then +if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -4534,24 +4683,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4561,9 +4710,9 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -4574,24 +4723,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4600,12 +4749,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB @@ -4682,9 +4827,9 @@ compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. -{ $as_echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } -if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -4800,18 +4945,18 @@ void nm_test_func(void){} int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm - if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s "$nlist"; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" @@ -4864,11 +5009,11 @@ _LT_EOF lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext}; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" @@ -4902,10 +5047,10 @@ if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { $as_echo "$as_me:$LINENO: result: failed" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else - { $as_echo "$as_me:$LINENO: result: ok" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi @@ -4932,7 +5077,7 @@ fi # Check whether --enable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then +if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi @@ -4944,11 +5089,11 @@ case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" @@ -4962,12 +5107,12 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4965 "configure"' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + echo '#line 5110 "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) @@ -5001,11 +5146,11 @@ x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in @@ -5054,9 +5199,9 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" - { $as_echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } -if test "${lt_cv_cc_needs_belf+set}" = set; then +if test "${lt_cv_cc_needs_belf+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_ext=c @@ -5065,11 +5210,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -5080,38 +5221,13 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - lt_cv_cc_needs_belf=no + lt_cv_cc_needs_belf=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5119,7 +5235,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf @@ -5129,11 +5245,11 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in @@ -5159,9 +5275,9 @@ need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DSYMUTIL+set}" = set; then +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then @@ -5172,24 +5288,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then - { $as_echo "$as_me:$LINENO: result: $DSYMUTIL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5199,9 +5315,9 @@ if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then @@ -5212,24 +5328,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_DSYMUTIL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5238,12 +5354,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL @@ -5255,9 +5367,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_NMEDIT+set}" = set; then +if test "${ac_cv_prog_NMEDIT+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then @@ -5268,24 +5380,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then - { $as_echo "$as_me:$LINENO: result: $NMEDIT" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5295,9 +5407,9 @@ if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then @@ -5308,24 +5420,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_NMEDIT="nmedit" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_NMEDIT" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5334,12 +5446,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT @@ -5351,9 +5459,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_LIPO+set}" = set; then +if test "${ac_cv_prog_LIPO+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then @@ -5364,24 +5472,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then - { $as_echo "$as_me:$LINENO: result: $LIPO" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5391,9 +5499,9 @@ if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then @@ -5404,24 +5512,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_LIPO="lipo" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_LIPO" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5430,12 +5538,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO @@ -5447,9 +5551,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL+set}" = set; then +if test "${ac_cv_prog_OTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then @@ -5460,24 +5564,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then - { $as_echo "$as_me:$LINENO: result: $OTOOL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5487,9 +5591,9 @@ if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then @@ -5500,24 +5604,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL="otool" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5526,12 +5630,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL @@ -5543,9 +5643,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL64+set}" = set; then +if test "${ac_cv_prog_OTOOL64+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then @@ -5556,24 +5656,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then - { $as_echo "$as_me:$LINENO: result: $OTOOL64" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5583,9 +5683,9 @@ if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then @@ -5596,24 +5696,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL64="otool64" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL64" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5622,12 +5722,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 @@ -5662,9 +5758,9 @@ fi - { $as_echo "$as_me:$LINENO: checking for -single_module linker flag" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } -if test "${lt_cv_apple_cc_single_mod+set}" = set; then +if test "${lt_cv_apple_cc_single_mod+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no @@ -5689,22 +5785,18 @@ else rm -f conftest.* fi fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_apple_cc_single_mod" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } - { $as_echo "$as_me:$LINENO: checking for -exported_symbols_list linker flag" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } -if test "${lt_cv_ld_exported_symbols_list+set}" = set; then +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -5715,42 +5807,17 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - lt_cv_ld_exported_symbols_list=no + lt_cv_ld_exported_symbols_list=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_exported_symbols_list" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } case $host_os in rhapsody* | darwin1.[012]) @@ -5792,14 +5859,14 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then + if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -5814,11 +5881,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -5827,78 +5890,34 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then +if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : break fi @@ -5910,7 +5929,7 @@ fi else ac_cv_prog_CPP=$CPP fi -{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes @@ -5921,11 +5940,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -5934,85 +5949,40 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then +if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - : +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + else - { { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c @@ -6022,16 +5992,12 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then +if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -6046,48 +6012,23 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_header_stdc=no + ac_cv_header_stdc=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : + $EGREP "memchr" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -6097,18 +6038,14 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : + $EGREP "free" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -6118,14 +6055,10 @@ fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then + if test "$cross_compiling" = yes; then : : else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -6152,117 +6085,33 @@ main () return 0; } _ACEOF -rm -f conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : +if ac_fn_c_try_run "$LINENO"; then : + else - $as_echo "$as_me: program exited with status $ac_status" >&5 -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_header_stdc=no + ac_cv_header_stdc=no fi -rm -rf conftest.dSYM -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext fi - fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then -cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 -_ACEOF +$as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. - - - - - - - - - for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h -do -as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - eval "$as_ac_Header=yes" -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_Header=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` = yes; then +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -6272,61 +6121,13 @@ fi done - for ac_header in dlfcn.h -do -as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - eval "$as_ac_Header=yes" -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_Header=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` = yes; then +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_DLFCN_H 1 _ACEOF fi @@ -6346,7 +6147,7 @@ done # Check whether --enable-shared was given. -if test "${enable_shared+set}" = set; then +if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; @@ -6377,7 +6178,7 @@ fi # Check whether --enable-static was given. -if test "${enable_static+set}" = set; then +if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; @@ -6409,7 +6210,7 @@ fi # Check whether --with-pic was given. -if test "${with_pic+set}" = set; then +if test "${with_pic+set}" = set; then : withval=$with_pic; pic_mode="$withval" else pic_mode=default @@ -6425,7 +6226,7 @@ test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. -if test "${enable_fast_install+set}" = set; then +if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; @@ -6506,9 +6307,9 @@ if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi -{ $as_echo "$as_me:$LINENO: checking for objdir" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } -if test "${lt_cv_objdir+set}" = set; then +if test "${lt_cv_objdir+set}" = set; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null @@ -6521,7 +6322,7 @@ else fi rmdir .libs 2>/dev/null fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir @@ -6614,9 +6415,9 @@ test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { $as_echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in @@ -6667,10 +6468,10 @@ fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -6680,9 +6481,9 @@ fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then - { $as_echo "$as_me:$LINENO: checking for file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in @@ -6733,10 +6534,10 @@ fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -6813,9 +6614,9 @@ lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag=' -fno-builtin' - { $as_echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no @@ -6831,11 +6632,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6834: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6635: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6838: \$? = $ac_status" >&5 + echo "$as_me:6639: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -6848,7 +6649,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then @@ -6868,7 +6669,7 @@ fi lt_prog_compiler_pic= lt_prog_compiler_static= -{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then @@ -7140,7 +6941,7 @@ case $host_os in lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac -{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 $as_echo "$lt_prog_compiler_pic" >&6; } @@ -7152,9 +6953,9 @@ $as_echo "$lt_prog_compiler_pic" >&6; } # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then - { $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test "${lt_cv_prog_compiler_pic_works+set}" = set; then +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no @@ -7170,11 +6971,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7173: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6974: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7177: \$? = $ac_status" >&5 + echo "$as_me:6978: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7187,7 +6988,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then @@ -7211,9 +7012,9 @@ fi # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test "${lt_cv_prog_compiler_static_works+set}" = set; then +if test "${lt_cv_prog_compiler_static_works+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no @@ -7239,7 +7040,7 @@ else LDFLAGS="$save_LDFLAGS" fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then @@ -7254,9 +7055,9 @@ fi - { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no @@ -7275,11 +7076,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7278: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7079: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7282: \$? = $ac_status" >&5 + echo "$as_me:7083: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7301,7 +7102,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } @@ -7309,9 +7110,9 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; } - { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no @@ -7330,11 +7131,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7333: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7134: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7337: \$? = $ac_status" >&5 + echo "$as_me:7138: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7356,7 +7157,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } @@ -7365,7 +7166,7 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user - { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* @@ -7373,10 +7174,10 @@ $as_echo_n "checking if we can lock with hard links... " >&6; } touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no - { $as_echo "$as_me:$LINENO: result: $hard_links" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then - { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi @@ -7389,7 +7190,7 @@ fi - { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= @@ -7831,11 +7632,7 @@ _LT_EOF allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -7846,27 +7643,7 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { @@ -7880,16 +7657,9 @@ aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpat if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" @@ -7902,11 +7672,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi else # Determine the default libpath from the value encoded in an # empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -7917,27 +7683,7 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { @@ -7951,16 +7697,9 @@ aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpat if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" @@ -8172,42 +7911,16 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" - cat >conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ int foo(void) {} _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' @@ -8463,7 +8176,7 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ fi fi -{ $as_echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no @@ -8500,16 +8213,16 @@ x|xyes) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. - { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } 2>conftest.err; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext @@ -8523,11 +8236,11 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= - if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } then archive_cmds_need_lc=no else @@ -8538,7 +8251,7 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } cat conftest.err 1>&5 fi $RM conftest* - { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 $as_echo "$archive_cmds_need_lc" >&6; } ;; esac @@ -8702,7 +8415,7 @@ esac - { $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then @@ -9137,11 +8850,7 @@ linux* | k*bsd*-gnu) save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -9152,41 +8861,13 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : shlibpath_overrides_runpath=yes fi - -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir @@ -9398,7 +9079,7 @@ uts4*) dynamic_linker=no ;; esac -{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no @@ -9500,7 +9181,7 @@ fi - { $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || @@ -9525,7 +9206,7 @@ else # directories. hardcode_action=unsupported fi -{ $as_echo "$as_me:$LINENO: result: $hardcode_action" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || @@ -9570,18 +9251,14 @@ else darwin*) # if libdl is installed we need to link against it - { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9599,43 +9276,18 @@ return dlopen (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dl_dlopen=no + ac_cv_lib_dl_dlopen=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test $ac_cv_lib_dl_dlopen = yes; then +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else @@ -9648,106 +9300,18 @@ fi ;; *) - { $as_echo "$as_me:$LINENO: checking for shl_load" >&5 -$as_echo_n "checking for shl_load... " >&6; } -if test "${ac_cv_func_shl_load+set}" = set; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define shl_load to an innocuous variant, in case declares shl_load. - For example, HP-UX 11i declares gettimeofday. */ -#define shl_load innocuous_shl_load - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char shl_load (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef shl_load - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_shl_load || defined __stub___shl_load -choke me -#endif - -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - ac_cv_func_shl_load=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func_shl_load=no -fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 -$as_echo "$ac_cv_func_shl_load" >&6; } -if test $ac_cv_func_shl_load = yes; then + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : lt_cv_dlopen="shl_load" else - { $as_echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9765,145 +9329,32 @@ return shl_load (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_shl_load=no + ac_cv_lib_dld_shl_load=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test $ac_cv_lib_dld_shl_load = yes; then +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else - { $as_echo "$as_me:$LINENO: checking for dlopen" >&5 -$as_echo_n "checking for dlopen... " >&6; } -if test "${ac_cv_func_dlopen+set}" = set; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define dlopen to an innocuous variant, in case declares dlopen. - For example, HP-UX 11i declares gettimeofday. */ -#define dlopen innocuous_dlopen - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char dlopen (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef dlopen - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_dlopen || defined __stub___dlopen -choke me -#endif - -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - ac_cv_func_dlopen=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func_dlopen=no -fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 -$as_echo "$ac_cv_func_dlopen" >&6; } -if test $ac_cv_func_dlopen = yes; then + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" else - { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9921,57 +9372,28 @@ return dlopen (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dl_dlopen=no + ac_cv_lib_dl_dlopen=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test $ac_cv_lib_dl_dlopen = yes; then +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else - { $as_echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } -if test "${ac_cv_lib_svld_dlopen+set}" = set; then +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9989,57 +9411,28 @@ return dlopen (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_svld_dlopen=no + ac_cv_lib_svld_dlopen=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } -if test $ac_cv_lib_svld_dlopen = yes; then +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else - { $as_echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } -if test "${ac_cv_lib_dld_dld_link+set}" = set; then +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -10057,43 +9450,18 @@ return dld_link (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_dld_link=no + ac_cv_lib_dld_dld_link=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } -if test $ac_cv_lib_dld_dld_link = yes; then +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi @@ -10132,9 +9500,9 @@ fi save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" - { $as_echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self+set}" = set; then +if test "${lt_cv_dlopen_self+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10143,7 +9511,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10146 "configure" +#line 9514 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10202,11 +9570,11 @@ int main () return status; } _LT_EOF - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -10223,14 +9591,14 @@ rm -fr conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { $as_echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self_static+set}" = set; then +if test "${lt_cv_dlopen_self_static+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10239,7 +9607,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10242 "configure" +#line 9610 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10298,11 +9666,11 @@ int main () return status; } _LT_EOF - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -10319,7 +9687,7 @@ rm -fr conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi @@ -10358,12 +9726,12 @@ fi striplib= old_striplib= -{ $as_echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough @@ -10372,15 +9740,15 @@ else if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac @@ -10398,12 +9766,12 @@ fi # Report which library types will actually be built - { $as_echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } - { $as_echo "$as_me:$LINENO: result: $can_build_shared" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } - { $as_echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no @@ -10424,14 +9792,14 @@ $as_echo_n "checking whether to build shared libraries... " >&6; } fi ;; esac - { $as_echo "$as_me:$LINENO: result: $enable_shared" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } - { $as_echo "$as_me:$LINENO: checking whether to build static libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes - { $as_echo "$as_me:$LINENO: result: $enable_static" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } @@ -10480,10 +9848,10 @@ CC="$lt_save_CC" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then +if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10491,11 +9859,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in - ./ | .// | /cC/* | \ + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. @@ -10532,7 +9900,7 @@ case $as_dir/ in ;; esac -done + done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir @@ -10548,7 +9916,7 @@ fi INSTALL=$ac_install_sh fi fi -{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. @@ -10563,9 +9931,9 @@ for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AWK+set}" = set; then +if test "${ac_cv_prog_AWK+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then @@ -10576,24 +9944,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then - { $as_echo "$as_me:$LINENO: result: $AWK" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -10606,15 +9974,15 @@ done # Enable large file support (if special flags are necessary) # # Check whether --enable-largefile was given. -if test "${enable_largefile+set}" = set; then +if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then - { $as_echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } -if test "${ac_cv_sys_largefile_CC+set}" = set; then +if test "${ac_cv_sys_largefile_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no @@ -10623,11 +9991,7 @@ else while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. @@ -10646,60 +10010,14 @@ main () return 0; } _ACEOF - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then + if ac_fn_c_try_compile "$LINENO"; then : break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then + if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext break done @@ -10707,23 +10025,19 @@ rm -f core conftest.err conftest.$ac_objext rm -f conftest.$ac_ext fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi - { $as_echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } -if test "${ac_cv_sys_file_offset_bits+set}" = set; then +if test "${ac_cv_sys_file_offset_bits+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. @@ -10742,38 +10056,11 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include @@ -10793,38 +10080,15 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; @@ -10836,17 +10100,13 @@ _ACEOF esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then - { $as_echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } -if test "${ac_cv_sys_large_files+set}" = set; then +if test "${ac_cv_sys_large_files+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. @@ -10865,38 +10125,11 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include @@ -10916,38 +10149,15 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; @@ -10964,101 +10174,8 @@ fi ######### # Check for needed/wanted data types -{ $as_echo "$as_me:$LINENO: checking for int8_t" >&5 -$as_echo_n "checking for int8_t... " >&6; } -if test "${ac_cv_type_int8_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int8_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int8_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int8_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int8_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int8_t" >&5 -$as_echo "$ac_cv_type_int8_t" >&6; } -if test $ac_cv_type_int8_t = yes; then +ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default" +if test "x$ac_cv_type_int8_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT8_T 1 @@ -11066,101 +10183,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for int16_t" >&5 -$as_echo_n "checking for int16_t... " >&6; } -if test "${ac_cv_type_int16_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int16_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int16_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int16_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int16_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5 -$as_echo "$ac_cv_type_int16_t" >&6; } -if test $ac_cv_type_int16_t = yes; then +ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default" +if test "x$ac_cv_type_int16_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT16_T 1 @@ -11168,101 +10192,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for int32_t" >&5 -$as_echo_n "checking for int32_t... " >&6; } -if test "${ac_cv_type_int32_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int32_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int32_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int32_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int32_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5 -$as_echo "$ac_cv_type_int32_t" >&6; } -if test $ac_cv_type_int32_t = yes; then +ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default" +if test "x$ac_cv_type_int32_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT32_T 1 @@ -11270,101 +10201,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for int64_t" >&5 -$as_echo_n "checking for int64_t... " >&6; } -if test "${ac_cv_type_int64_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int64_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int64_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int64_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int64_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5 -$as_echo "$ac_cv_type_int64_t" >&6; } -if test $ac_cv_type_int64_t = yes; then +ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default" +if test "x$ac_cv_type_int64_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT64_T 1 @@ -11372,101 +10210,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for intptr_t" >&5 -$as_echo_n "checking for intptr_t... " >&6; } -if test "${ac_cv_type_intptr_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_intptr_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (intptr_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((intptr_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_intptr_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_intptr_t" >&5 -$as_echo "$ac_cv_type_intptr_t" >&6; } -if test $ac_cv_type_intptr_t = yes; then +ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "$ac_includes_default" +if test "x$ac_cv_type_intptr_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INTPTR_T 1 @@ -11474,101 +10219,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint8_t" >&5 -$as_echo_n "checking for uint8_t... " >&6; } -if test "${ac_cv_type_uint8_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint8_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint8_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint8_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint8_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint8_t" >&5 -$as_echo "$ac_cv_type_uint8_t" >&6; } -if test $ac_cv_type_uint8_t = yes; then +ac_fn_c_check_type "$LINENO" "uint8_t" "ac_cv_type_uint8_t" "$ac_includes_default" +if test "x$ac_cv_type_uint8_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT8_T 1 @@ -11576,101 +10228,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint16_t" >&5 -$as_echo_n "checking for uint16_t... " >&6; } -if test "${ac_cv_type_uint16_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint16_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint16_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint16_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint16_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5 -$as_echo "$ac_cv_type_uint16_t" >&6; } -if test $ac_cv_type_uint16_t = yes; then +ac_fn_c_check_type "$LINENO" "uint16_t" "ac_cv_type_uint16_t" "$ac_includes_default" +if test "x$ac_cv_type_uint16_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT16_T 1 @@ -11678,101 +10237,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint32_t" >&5 -$as_echo_n "checking for uint32_t... " >&6; } -if test "${ac_cv_type_uint32_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint32_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint32_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint32_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint32_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5 -$as_echo "$ac_cv_type_uint32_t" >&6; } -if test $ac_cv_type_uint32_t = yes; then +ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "$ac_includes_default" +if test "x$ac_cv_type_uint32_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT32_T 1 @@ -11780,101 +10246,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint64_t" >&5 -$as_echo_n "checking for uint64_t... " >&6; } -if test "${ac_cv_type_uint64_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint64_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint64_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint64_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint64_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5 -$as_echo "$ac_cv_type_uint64_t" >&6; } -if test $ac_cv_type_uint64_t = yes; then +ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default" +if test "x$ac_cv_type_uint64_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT64_T 1 @@ -11882,101 +10255,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uintptr_t" >&5 -$as_echo_n "checking for uintptr_t... " >&6; } -if test "${ac_cv_type_uintptr_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uintptr_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uintptr_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uintptr_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uintptr_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uintptr_t" >&5 -$as_echo "$ac_cv_type_uintptr_t" >&6; } -if test $ac_cv_type_uintptr_t = yes; then +ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "$ac_includes_default" +if test "x$ac_cv_type_uintptr_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 @@ -11988,146 +10268,11 @@ fi ######### # Check for needed/wanted headers - - - - for ac_header in sys/types.h stdlib.h stdint.h inttypes.h -do -as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 -$as_echo_n "checking $ac_header usability... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 -$as_echo_n "checking $ac_header presence... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - - ;; -esac -{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - -fi -if test `eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` = yes; then +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -12140,104 +10285,11 @@ done ######### # Figure out whether or not we have these functions # - - - - - - for ac_func in usleep fdatasync localtime_r gmtime_r localtime_s utime -do -as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 -$as_echo_n "checking for $ac_func... " >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - eval "$as_ac_var=yes" -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval 'as_val=${'$as_ac_var'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_var'} - $as_echo "$as_val"'` = yes; then +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -12260,9 +10312,9 @@ for ac_prog in tclsh8.5 tclsh do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_TCLSH_CMD+set}" = set; then +if test "${ac_cv_prog_TCLSH_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$TCLSH_CMD"; then @@ -12273,24 +10325,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_TCLSH_CMD="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi TCLSH_CMD=$ac_cv_prog_TCLSH_CMD if test -n "$TCLSH_CMD"; then - { $as_echo "$as_me:$LINENO: result: $TCLSH_CMD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_CMD" >&5 $as_echo "$TCLSH_CMD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -12328,17 +10380,17 @@ fi VERSION=`cat $srcdir/VERSION | sed 's/^\([0-9]*\.*[0-9]*\).*/\1/'` -{ $as_echo "$as_me:$LINENO: Version set to $VERSION" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: Version set to $VERSION" >&5 $as_echo "$as_me: Version set to $VERSION" >&6;} RELEASE=`cat $srcdir/VERSION` -{ $as_echo "$as_me:$LINENO: Release set to $RELEASE" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5 $as_echo "$as_me: Release set to $RELEASE" >&6;} VERSION_NUMBER=`cat $srcdir/VERSION \ | sed 's/[^0-9]/ /g' \ | awk '{printf "%d%03d%03d",$1,$2,$3}'` -{ $as_echo "$as_me:$LINENO: Version number set to $VERSION_NUMBER" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: Version number set to $VERSION_NUMBER" >&5 $as_echo "$as_me: Version number set to $VERSION_NUMBER" >&6;} @@ -12351,7 +10403,7 @@ $as_echo "$as_me: Version number set to $VERSION_NUMBER" >&6;} # # Check whether --with-hints was given. -if test "${with_hints+set}" = set; then +if test "${with_hints+set}" = set; then : withval=$with_hints; hints=$withval fi @@ -12376,7 +10428,7 @@ if test "$hints" = ""; then fi fi if test "$hints" != ""; then - { $as_echo "$as_me:$LINENO: result: reading hints from $hints" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: reading hints from $hints" >&5 $as_echo "reading hints from $hints" >&6; } . $hints fi @@ -12394,9 +10446,9 @@ else do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_BUILD_CC+set}" = set; then +if test "${ac_cv_prog_BUILD_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$BUILD_CC"; then @@ -12407,24 +10459,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_BUILD_CC="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi BUILD_CC=$ac_cv_prog_BUILD_CC if test -n "$BUILD_CC"; then - { $as_echo "$as_me:$LINENO: result: $BUILD_CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_CC" >&5 $as_echo "$BUILD_CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -12443,37 +10495,33 @@ fi # Do we want to support multithreaded use of sqlite # # Check whether --enable-threadsafe was given. -if test "${enable_threadsafe+set}" = set; then +if test "${enable_threadsafe+set}" = set; then : enableval=$enable_threadsafe; else enable_threadsafe=yes fi -{ $as_echo "$as_me:$LINENO: checking whether to support threadsafe operation" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support threadsafe operation" >&5 $as_echo_n "checking whether to support threadsafe operation... " >&6; } if test "$enable_threadsafe" = "no"; then SQLITE_THREADSAFE=0 - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else SQLITE_THREADSAFE=1 - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi if test "$SQLITE_THREADSAFE" = "1"; then - { $as_echo "$as_me:$LINENO: checking for library containing pthread_create" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 $as_echo_n "checking for library containing pthread_create... " >&6; } -if test "${ac_cv_search_pthread_create+set}" = set; then +if test "${ac_cv_search_pthread_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -12498,54 +10546,27 @@ for ac_lib in '' pthread; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_pthread_create=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_pthread_create+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_pthread_create+set}" = set; then : break fi done -if test "${ac_cv_search_pthread_create+set}" = set; then - : +if test "${ac_cv_search_pthread_create+set}" = set; then : + else ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_pthread_create" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 $as_echo "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -12558,21 +10579,21 @@ fi # due to bugs in the threading implementations. This is thus off by default. # # Check whether --enable-cross-thread-connections was given. -if test "${enable_cross_thread_connections+set}" = set; then +if test "${enable_cross_thread_connections+set}" = set; then : enableval=$enable_cross_thread_connections; else enable_xthreadconnect=no fi -{ $as_echo "$as_me:$LINENO: checking whether to allow connections to be shared across threads" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to allow connections to be shared across threads" >&5 $as_echo_n "checking whether to allow connections to be shared across threads... " >&6; } if test "$enable_xthreadconnect" = "no"; then XTHREADCONNECT='' - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else XTHREADCONNECT='-DSQLITE_ALLOW_XTHREAD_CONNECT=1' - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi @@ -12581,21 +10602,21 @@ fi # Do we want to support release # # Check whether --enable-releasemode was given. -if test "${enable_releasemode+set}" = set; then +if test "${enable_releasemode+set}" = set; then : enableval=$enable_releasemode; else enable_releasemode=no fi -{ $as_echo "$as_me:$LINENO: checking whether to support shared library linked as release mode or not" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support shared library linked as release mode or not" >&5 $as_echo_n "checking whether to support shared library linked as release mode or not... " >&6; } if test "$enable_releasemode" = "no"; then ALLOWRELEASE="" - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else ALLOWRELEASE="-release `cat $srcdir/VERSION`" - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi @@ -12604,38 +10625,38 @@ fi # Do we want temporary databases in memory # # Check whether --enable-tempstore was given. -if test "${enable_tempstore+set}" = set; then +if test "${enable_tempstore+set}" = set; then : enableval=$enable_tempstore; else enable_tempstore=no fi -{ $as_echo "$as_me:$LINENO: checking whether to use an in-ram database for temporary tables" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use an in-ram database for temporary tables" >&5 $as_echo_n "checking whether to use an in-ram database for temporary tables... " >&6; } case "$enable_tempstore" in never ) TEMP_STORE=0 - { $as_echo "$as_me:$LINENO: result: never" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: never" >&5 $as_echo "never" >&6; } ;; no ) TEMP_STORE=1 - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; yes ) TEMP_STORE=2 - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ;; always ) TEMP_STORE=3 - { $as_echo "$as_me:$LINENO: result: always" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: always" >&5 $as_echo "always" >&6; } ;; * ) TEMP_STORE=1 - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac @@ -12647,53 +10668,17 @@ esac # the CYGWIN environment. So check for that special case and handle # things accordingly. # -{ $as_echo "$as_me:$LINENO: checking if executables have the .exe suffix" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if executables have the .exe suffix" >&5 $as_echo_n "checking if executables have the .exe suffix... " >&6; } if test "$config_BUILD_EXEEXT" = ".exe"; then CYGWIN=yes - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else - { $as_echo "$as_me:$LINENO: result: unknown" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 $as_echo "unknown" >&6; } fi if test "$CYGWIN" != "yes"; then - { $as_echo "$as_me:$LINENO: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if test "${ac_cv_host+set}" = set; then - $as_echo_n "(cached) " >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 -$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} - { (exit 1); exit 1; }; } -fi - -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 -$as_echo "$as_me: error: invalid value of canonical host" >&2;} - { (exit 1); exit 1; }; };; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - case $host_os in *cygwin* ) CYGWIN=yes;; @@ -12745,7 +10730,7 @@ fi # minor changes to accomodate systems that do not have TCL installed. # # Check whether --enable-tcl was given. -if test "${enable_tcl+set}" = set; then +if test "${enable_tcl+set}" = set; then : enableval=$enable_tcl; use_tcl=$enableval else use_tcl=yes @@ -12754,13 +10739,13 @@ fi if test "${use_tcl}" = "yes" ; then # Check whether --with-tcl was given. -if test "${with_tcl+set}" = set; then +if test "${with_tcl+set}" = set; then : withval=$with_tcl; with_tclconfig=${withval} fi - { $as_echo "$as_me:$LINENO: checking for Tcl configuration" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 $as_echo_n "checking for Tcl configuration... " >&6; } - if test "${ac_cv_c_tclconfig+set}" = set; then + if test "${ac_cv_c_tclconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12769,9 +10754,7 @@ else if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else - { { $as_echo "$as_me:$LINENO: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&5 -$as_echo "$as_me: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 fi fi @@ -12844,25 +10827,25 @@ fi if test x"${ac_cv_c_tclconfig}" = x ; then use_tcl=no - { $as_echo "$as_me:$LINENO: WARNING: Can't find Tcl configuration definitions" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find Tcl configuration definitions" >&5 $as_echo "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5 $as_echo "$as_me: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5 $as_echo "$as_me: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&2;} else TCL_BIN_DIR=${ac_cv_c_tclconfig} - { $as_echo "$as_me:$LINENO: result: found $TCL_BIN_DIR/tclConfig.sh" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $TCL_BIN_DIR/tclConfig.sh" >&5 $as_echo "found $TCL_BIN_DIR/tclConfig.sh" >&6; } - { $as_echo "$as_me:$LINENO: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5 $as_echo_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh... " >&6; } if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then - { $as_echo "$as_me:$LINENO: result: loading" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . $TCL_BIN_DIR/tclConfig.sh else - { $as_echo "$as_me:$LINENO: result: file not found" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: file not found" >&5 $as_echo "file not found" >&6; } fi @@ -12923,7 +10906,7 @@ TARGET_READLINE_LIBS="" TARGET_READLINE_INC="" TARGET_HAVE_READLINE=0 # Check whether --enable-readline was given. -if test "${enable_readline+set}" = set; then +if test "${enable_readline+set}" = set; then : enableval=$enable_readline; with_readline=$enableval else with_readline=auto @@ -12935,7 +10918,7 @@ if test x"$with_readline" != xno; then # Check whether --with-readline-lib was given. -if test "${with_readline_lib+set}" = set; then +if test "${with_readline_lib+set}" = set; then : withval=$with_readline_lib; with_readline_lib=$withval else with_readline_lib="auto" @@ -12944,17 +10927,13 @@ fi if test "x$with_readline_lib" = xauto; then save_LIBS="$LIBS" LIBS="" - { $as_echo "$as_me:$LINENO: checking for library containing tgetent" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5 $as_echo_n "checking for library containing tgetent... " >&6; } -if test "${ac_cv_search_tgetent+set}" = set; then +if test "${ac_cv_search_tgetent+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -12979,72 +10958,41 @@ for ac_lib in '' readline ncurses curses termcap; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_tgetent=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_tgetent+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_tgetent+set}" = set; then : break fi done -if test "${ac_cv_search_tgetent+set}" = set; then - : +if test "${ac_cv_search_tgetent+set}" = set; then : + else ac_cv_search_tgetent=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_tgetent" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5 $as_echo "$ac_cv_search_tgetent" >&6; } ac_res=$ac_cv_search_tgetent -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" term_LIBS="$LIBS" else term_LIBS="" fi - { $as_echo "$as_me:$LINENO: checking for readline in -lreadline" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5 $as_echo_n "checking for readline in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_readline+set}" = set; then +if test "${ac_cv_lib_readline_readline+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -13062,43 +11010,18 @@ return readline (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_readline=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_readline_readline=no + ac_cv_lib_readline_readline=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 $as_echo "$ac_cv_lib_readline_readline" >&6; } -if test $ac_cv_lib_readline_readline = yes; then +if test "x$ac_cv_lib_readline_readline" = x""yes; then : TARGET_READLINE_LIBS="-lreadline" else found="no" @@ -13112,141 +11035,15 @@ fi # Check whether --with-readline-inc was given. -if test "${with_readline_inc+set}" = set; then +if test "${with_readline_inc+set}" = set; then : withval=$with_readline_inc; with_readline_inc=$withval else with_readline_inc="auto" fi if test "x$with_readline_inc" = xauto; then - if test "${ac_cv_header_readline_h+set}" = set; then - { $as_echo "$as_me:$LINENO: checking for readline.h" >&5 -$as_echo_n "checking for readline.h... " >&6; } -if test "${ac_cv_header_readline_h+set}" = set; then - $as_echo_n "(cached) " >&6 -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_readline_h" >&5 -$as_echo "$ac_cv_header_readline_h" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:$LINENO: checking readline.h usability" >&5 -$as_echo_n "checking readline.h usability... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:$LINENO: checking readline.h presence" >&5 -$as_echo_n "checking readline.h presence... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { $as_echo "$as_me:$LINENO: WARNING: readline.h: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: readline.h: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: readline.h: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { $as_echo "$as_me:$LINENO: WARNING: readline.h: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: readline.h: present but cannot be compiled" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: readline.h: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: readline.h: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: readline.h: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: proceeding with the preprocessor's result" >&5 -$as_echo "$as_me: WARNING: readline.h: proceeding with the preprocessor's result" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: in the future, the compiler will take precedence" >&5 -$as_echo "$as_me: WARNING: readline.h: in the future, the compiler will take precedence" >&2;} - - ;; -esac -{ $as_echo "$as_me:$LINENO: checking for readline.h" >&5 -$as_echo_n "checking for readline.h... " >&6; } -if test "${ac_cv_header_readline_h+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_header_readline_h=$ac_header_preproc -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_readline_h" >&5 -$as_echo "$ac_cv_header_readline_h" >&6; } - -fi -if test $ac_cv_header_readline_h = yes; then + ac_fn_c_check_header_mongrel "$LINENO" "readline.h" "ac_cv_header_readline_h" "$ac_includes_default" +if test "x$ac_cv_header_readline_h" = x""yes; then : found="yes" else @@ -13255,27 +11052,23 @@ else for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do for subdir in include include/readline; do as_ac_File=`$as_echo "ac_cv_file_$dir/$subdir/readline.h" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $dir/$subdir/readline.h" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $dir/$subdir/readline.h" >&5 $as_echo_n "checking for $dir/$subdir/readline.h... " >&6; } -if { as_var=$as_ac_File; eval "test \"\${$as_var+set}\" = set"; }; then +if eval "test \"\${$as_ac_File+set}\"" = set; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && - { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 -$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$dir/$subdir/readline.h"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi -ac_res=`eval 'as_val=${'$as_ac_File'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +eval ac_res=\$$as_ac_File + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_File'} - $as_echo "$as_val"'` = yes; then +if eval test \"x\$"$as_ac_File"\" = x"yes"; then : found=yes fi @@ -13312,17 +11105,13 @@ fi # Figure out what C libraries are required to compile programs # that use "fdatasync()" function. # -{ $as_echo "$as_me:$LINENO: checking for library containing fdatasync" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5 $as_echo_n "checking for library containing fdatasync... " >&6; } -if test "${ac_cv_search_fdatasync+set}" = set; then +if test "${ac_cv_search_fdatasync+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -13347,54 +11136,27 @@ for ac_lib in '' rt; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_fdatasync=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_fdatasync+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_fdatasync+set}" = set; then : break fi done -if test "${ac_cv_search_fdatasync+set}" = set; then - : +if test "${ac_cv_search_fdatasync+set}" = set; then : + else ac_cv_search_fdatasync=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_fdatasync" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fdatasync" >&5 $as_echo "$ac_cv_search_fdatasync" >&6; } ac_res=$ac_cv_search_fdatasync -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -13403,7 +11165,7 @@ fi ######### # check for debug enabled # Check whether --enable-debug was given. -if test "${enable_debug+set}" = set; then +if test "${enable_debug+set}" = set; then : enableval=$enable_debug; use_debug=$enableval else use_debug=no @@ -13419,7 +11181,7 @@ fi ######### # See whether we should use the amalgamation to build # Check whether --enable-amalgamation was given. -if test "${enable_amalgamation+set}" = set; then +if test "${enable_amalgamation+set}" = set; then : enableval=$enable_amalgamation; use_amalgamation=$enableval else use_amalgamation=yes @@ -13433,7 +11195,7 @@ fi ######### # See whether we should allow loadable extensions # Check whether --enable-load-extension was given. -if test "${enable_load_extension+set}" = set; then +if test "${enable_load_extension+set}" = set; then : enableval=$enable_load_extension; use_loadextension=$enableval else use_loadextension=no @@ -13441,17 +11203,13 @@ fi if test "${use_loadextension}" = "yes" ; then OPT_FEATURE_FLAGS="" - { $as_echo "$as_me:$LINENO: checking for library containing dlopen" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 $as_echo_n "checking for library containing dlopen... " >&6; } -if test "${ac_cv_search_dlopen+set}" = set; then +if test "${ac_cv_search_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -13476,54 +11234,27 @@ for ac_lib in '' dl; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_dlopen=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_dlopen+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_dlopen+set}" = set; then : break fi done -if test "${ac_cv_search_dlopen+set}" = set; then - : +if test "${ac_cv_search_dlopen+set}" = set; then : + else ac_cv_search_dlopen=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 $as_echo "$ac_cv_search_dlopen" >&6; } ac_res=$ac_cv_search_dlopen -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -13586,7 +11317,7 @@ BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS ######### # See whether we should use GCOV # Check whether --enable-gcov was given. -if test "${enable_gcov+set}" = set; then +if test "${enable_gcov+set}" = set; then : enableval=$enable_gcov; use_gcov=$enableval else use_gcov=no @@ -13638,13 +11369,13 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) $as_unset $ac_var ;; + *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done @@ -13652,8 +11383,8 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \). + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" @@ -13676,11 +11407,11 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && - { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else - { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi @@ -13694,14 +11425,15 @@ DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. - ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" - ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs @@ -13713,9 +11445,10 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. @@ -13725,17 +11458,18 @@ cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 debug=false ac_cs_recheck=false ac_cs_silent=false -SHELL=\${CONFIG_SHELL-$SHELL} -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which @@ -13743,23 +11477,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; esac - fi - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - as_nl=' ' export as_nl @@ -13767,7 +11493,13 @@ export as_nl as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else @@ -13778,7 +11510,7 @@ else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; - case $arg in + case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; @@ -13801,13 +11533,6 @@ if test "${PATH_SEPARATOR+set}" != set; then } fi -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false -fi - # IFS # We need space, tab and new line, in precisely that order. Quoting is @@ -13817,15 +11542,15 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -case $0 in +case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done IFS=$as_save_IFS ;; @@ -13837,12 +11562,16 @@ if test "x$as_myself" = x; then fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } + exit 1 fi -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' @@ -13854,7 +11583,89 @@ export LC_ALL LANGUAGE=C export LANGUAGE -# Required to use basename. +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr @@ -13868,8 +11679,12 @@ else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ @@ -13889,76 +11704,25 @@ $as_echo X/"$0" | } s/.*/./; q'` -# CDPATH. -$as_unset CDPATH - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } - - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in +case `echo -n x` in #((((( -n*) - case `echo 'x\c'` in + case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then @@ -13987,8 +11751,56 @@ fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false @@ -14007,10 +11819,10 @@ else if test -d "$1"; then test -d "$1/."; else - case $1 in + case $1 in #( -*)set "./$1";; esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' @@ -14025,13 +11837,19 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 -# Save the log message, to keep $[0] and so on meaningful, and to +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to # 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.7.7.1, which was -generated by GNU Autoconf 2.62. Invocation command line was +This file was extended by sqlite $as_me 3.7.9, which was +generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14044,6 +11862,15 @@ on `(hostname || uname -n) 2>/dev/null | sed 1q` _ACEOF +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" @@ -14054,19 +11881,22 @@ _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files from templates according to the -current configuration. +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. -Usage: $0 [OPTIONS] [FILE]... +Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit - -q, --quiet do not print progress messages + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] + --file=FILE[:TEMPLATE] instantiate the configuration file FILE - --header=FILE[:TEMPLATE] + --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: @@ -14078,16 +11908,17 @@ $config_headers Configuration commands: $config_commands -Report bugs to ." +Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sqlite config.status 3.7.7.1 -configured by $0, generated by GNU Autoconf 2.62, - with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" +sqlite config.status 3.7.9 +configured by $0, generated by GNU Autoconf 2.67, + with options \\"\$ac_cs_config\\" -Copyright (C) 2008 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -14104,11 +11935,16 @@ ac_need_defaults=: while test $# != 0 do case $1 in - --*=*) + --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; *) ac_option=$1 ac_optarg=$2 @@ -14122,27 +11958,29 @@ do ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; esac - CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" + as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac - CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'" + as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - { $as_echo "$as_me: error: ambiguous option: $1 -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; };; + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ @@ -14150,11 +11988,10 @@ Try \`$0 --help' for more information." >&2 ac_cs_silent=: ;; # This is an error. - -*) { $as_echo "$as_me: error: unrecognized option: $1 -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } ;; + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; - *) ac_config_targets="$ac_config_targets $1" + *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac @@ -14464,9 +12301,7 @@ do "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "sqlite3.pc") CONFIG_FILES="$CONFIG_FILES sqlite3.pc" ;; - *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 -$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} - { (exit 1); exit 1; }; };; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done @@ -14493,7 +12328,7 @@ $debug || trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 - trap '{ (exit 1); exit 1; }' 1 2 13 15 + trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. @@ -14504,11 +12339,7 @@ $debug || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || -{ - $as_echo "$as_me: cannot create a temporary directory in ." >&2 - { (exit 1); exit 1; } -} +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -14516,7 +12347,13 @@ $debug || if test -n "$CONFIG_FILES"; then -ac_cr=' ' +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' @@ -14533,23 +12370,18 @@ _ACEOF echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } -ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` = $ac_delim_num; then + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14571,7 +12403,7 @@ s/'"$ac_delim"'$// t delim :nl h -s/\(.\{148\}\).*/\1/ +s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p @@ -14585,7 +12417,7 @@ s/.\{148\}// t nl :delim h -s/\(.\{148\}\).*/\1/ +s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p @@ -14638,22 +12470,28 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 -$as_echo "$as_me: error: could not setup config files machinery" >&2;} - { (exit 1); exit 1; }; } + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// s/^[^=]*=[ ]*$// }' fi @@ -14681,9 +12519,7 @@ for ac_last_try in false false :; do if test -z "$ac_t"; then break elif $ac_last_try; then - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14749,9 +12585,9 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 } split(mac1, mac2, "(") #) macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". - prefix = substr(line, 1, index(line, defundef) - 1) print prefix "define", macro P[macro] D[macro] next } else { @@ -14759,7 +12595,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { - print "/*", line, "*/" + print "/*", prefix defundef, macro, "*/" next } } @@ -14768,9 +12604,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5 -$as_echo "$as_me: error: could not setup config headers machinery" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" @@ -14783,9 +12617,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 -$as_echo "$as_me: error: Invalid tag $ac_tag." >&2;} - { (exit 1); exit 1; }; };; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -14813,12 +12645,10 @@ $as_echo "$as_me: error: Invalid tag $ac_tag." >&2;} [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 -$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} - { (exit 1); exit 1; }; };; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - ac_file_inputs="$ac_file_inputs '$ac_f'" + as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't @@ -14829,7 +12659,7 @@ $as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. @@ -14842,9 +12672,7 @@ $as_echo "$as_me: creating $ac_file" >&6;} case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } ;; + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -14872,47 +12700,7 @@ $as_echo X"$ac_file" | q } s/.*/./; q'` - { as_dir="$ac_dir" - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 -$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} - { (exit 1); exit 1; }; }; } + as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in @@ -14964,7 +12752,6 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= - ac_sed_dataroot=' /datarootdir/ { p @@ -14974,12 +12761,11 @@ ac_sed_dataroot=' /@docdir@/p /@infodir@/p /@localedir@/p -/@mandir@/p -' +/@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 @@ -14989,7 +12775,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; + s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF @@ -15017,26 +12803,22 @@ s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&2;} +which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # @@ -15047,29 +12829,23 @@ $as_echo "$as_me: error: could not create $ac_file" >&2;} $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ - || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5 -$as_echo "$as_me: error: could not create -" >&2;} - { (exit 1); exit 1; }; } + || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; - :C) { $as_echo "$as_me:$LINENO: executing $ac_file commands" >&5 + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac @@ -15716,15 +13492,12 @@ _LT_EOF done # for ac_tag -{ (exit 0); exit 0; } +as_fn_exit 0 _ACEOF -chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || - { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. @@ -15745,10 +13518,10 @@ if test "$no_create" != yes; then exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. - $ac_cs_success || { (exit 1); exit 1; } + $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:$LINENO: WARNING: Unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi diff --git a/doc/lemon.html b/doc/lemon.html index 6a4d6dbd..2c655559 100644 --- a/doc/lemon.html +++ b/doc/lemon.html @@ -282,7 +282,7 @@ tokens) and it honors the same commenting conventions as C and C++.

A terminal symbol (token) is any string of alphanumeric and underscore characters that begins with an upper case letter. -A terminal can contain lower class letters after the first character, +A terminal can contain lowercase letters after the first character, but the usual convention is to make terminals all upper case. A nonterminal, on the other hand, is any string of alphanumeric and underscore characters than begins with a lower case letter. diff --git a/ext/fts3/README.content b/ext/fts3/README.content new file mode 100644 index 00000000..ab986754 --- /dev/null +++ b/ext/fts3/README.content @@ -0,0 +1,178 @@ + +FTS4 CONTENT OPTION + + Normally, in order to create a full-text index on a dataset, the FTS4 + module stores a copy of all indexed documents in a specially created + database table. + + As of SQLite version 3.7.9, FTS4 supports a new option - "content" - + designed to extend FTS4 to support the creation of full-text indexes where: + + * The indexed documents are not stored within the SQLite database + at all (a "contentless" FTS4 table), or + + * The indexed documents are stored in a database table created and + managed by the user (an "external content" FTS4 table). + + Because the indexed documents themselves are usually much larger than + the full-text index, the content option can sometimes be used to achieve + significant space savings. + +CONTENTLESS FTS4 TABLES + + In order to create an FTS4 table that does not store a copy of the indexed + documents at all, the content option should be set to an empty string. + For example, the following SQL creates such an FTS4 table with three + columns - "a", "b", and "c": + + CREATE VIRTUAL TABLE t1 USING fts4(content="", a, b, c); + + Data can be inserted into such an FTS4 table using an INSERT statements. + However, unlike ordinary FTS4 tables, the user must supply an explicit + integer docid value. For example: + + -- This statement is Ok: + INSERT INTO t1(docid, a, b, c) VALUES(1, 'a b c', 'd e f', 'g h i'); + + -- This statement causes an error, as no docid value has been provided: + INSERT INTO t1(a, b, c) VALUES('j k l', 'm n o', 'p q r'); + + It is not possible to UPDATE or DELETE a row stored in a contentless FTS4 + table. Attempting to do so is an error. + + Contentless FTS4 tables also support SELECT statements. However, it is + an error to attempt to retrieve the value of any table column other than + the docid column. The auxiliary function matchinfo() may be used, but + snippet() and offsets() may not. For example: + + -- The following statements are Ok: + SELECT docid FROM t1 WHERE t1 MATCH 'xxx'; + SELECT docid FROM t1 WHERE a MATCH 'xxx'; + SELECT matchinfo(t1) FROM t1 WHERE t1 MATCH 'xxx'; + + -- The following statements all cause errors, as the value of columns + -- other than docid are required to evaluate them. + SELECT * FROM t1; + SELECT a, b FROM t1 WHERE t1 MATCH 'xxx'; + SELECT docid FROM t1 WHERE a LIKE 'xxx%'; + SELECT snippet(t1) FROM t1 WHERE t1 MATCH 'xxx'; + + Errors related to attempting to retrieve column values other than docid + are runtime errors that occur within sqlite3_step(). In some cases, for + example if the MATCH expression in a SELECT query matches zero rows, there + may be no error at all even if a statement does refer to column values + other than docid. + +EXTERNAL CONTENT FTS4 TABLES + + An "external content" FTS4 table is similar to a contentless table, except + that if evaluation of a query requires the value of a column other than + docid, FTS4 attempts to retrieve that value from a table (or view, or + virtual table) nominated by the user (hereafter referred to as the "content + table"). The FTS4 module never writes to the content table, and writing + to the content table does not affect the full-text index. It is the + responsibility of the user to ensure that the content table and the + full-text index are consistent. + + An external content FTS4 table is created by setting the content option + to the name of a table (or view, or virtual table) that may be queried by + FTS4 to retrieve column values when required. If the nominated table does + not exist, then an external content table behaves in the same way as + a contentless table. For example: + + CREATE TABLE t2(id INTEGER PRIMARY KEY, a, b, c); + CREATE VIRTUAL TABLE t3 USING fts4(content="t2", a, c); + + Assuming the nominated table does exist, then its columns must be the same + as or a superset of those defined for the FTS table. + + When a users query on the FTS table requires a column value other than + docid, FTS attempts to read this value from the corresponding column of + the row in the content table with a rowid value equal to the current FTS + docid. Or, if such a row cannot be found in the content table, a NULL + value is used instead. For example: + + CREATE TABLE t2(id INTEGER PRIMARY KEY, a, b, c, d); + CREATE VIRTUAL TABLE t3 USING fts4(content="t2", b, c); + + INSERT INTO t2 VALUES(2, 'a b', 'c d', 'e f'); + INSERT INTO t2 VALUES(3, 'g h', 'i j', 'k l'); + INSERT INTO t3(docid, b, c) SELECT id, b, c FROM t2; + + -- The following query returns a single row with two columns containing + -- the text values "i j" and "k l". + -- + -- The query uses the full-text index to discover that the MATCH + -- term matches the row with docid=3. It then retrieves the values + -- of columns b and c from the row with rowid=3 in the content table + -- to return. + -- + SELECT * FROM t3 WHERE t3 MATCH 'k'; + + -- Following the UPDATE, the query still returns a single row, this + -- time containing the text values "xxx" and "yyy". This is because the + -- full-text index still indicates that the row with docid=3 matches + -- the FTS4 query 'k', even though the documents stored in the content + -- table have been modified. + -- + UPDATE t2 SET b = 'xxx', c = 'yyy' WHERE rowid = 3; + SELECT * FROM t3 WHERE t3 MATCH 'k'; + + -- Following the DELETE below, the query returns one row containing two + -- NULL values. NULL values are returned because FTS is unable to find + -- a row with rowid=3 within the content table. + -- + DELETE FROM t2; + SELECT * FROM t3 WHERE t3 MATCH 'k'; + + When a row is deleted from an external content FTS4 table, FTS4 needs to + retrieve the column values of the row being deleted from the content table. + This is so that FTS4 can update the full-text index entries for each token + that occurs within the deleted row to indicate that that row has been + deleted. If the content table row cannot be found, or if it contains values + inconsistent with the contents of the FTS index, the results can be difficult + to predict. The FTS index may be left containing entries corresponding to the + deleted row, which can lead to seemingly nonsensical results being returned + by subsequent SELECT queries. The same applies when a row is updated, as + internally an UPDATE is the same as a DELETE followed by an INSERT. + + Instead of writing separately to the full-text index and the content table, + some users may wish to use database triggers to keep the full-text index + up to date with respect to the set of documents stored in the content table. + For example, using the tables from earlier examples: + + CREATE TRIGGER t2_bu BEFORE UPDATE ON t2 BEGIN + DELETE FROM t3 WHERE docid=old.rowid; + END; + CREATE TRIGGER t2_bd BEFORE DELETE ON t2 BEGIN + DELETE FROM t3 WHERE docid=old.rowid; + END; + + CREATE TRIGGER t2_bu AFTER UPDATE ON t2 BEGIN + INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c); + END; + CREATE TRIGGER t2_bd AFTER INSERT ON t2 BEGIN + INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c); + END; + + The DELETE trigger must be fired before the actual delete takes place + on the content table. This is so that FTS4 can still retrieve the original + values in order to update the full-text index. And the INSERT trigger must + be fired after the new row is inserted, so as to handle the case where the + rowid is assigned automatically within the system. The UPDATE trigger must + be split into two parts, one fired before and one after the update of the + content table, for the same reasons. + + FTS4 features a special command similar to the 'optimize' command that + deletes the entire full-text index and rebuilds it based on the current + set of documents in the content table. Assuming again that "t3" is the + name of the external content FTS4 table, the command is: + + INSERT INTO t3(t3) VALUES('rebuild'); + + This command may also be used with ordinary FTS4 tables, although it may + only be useful if the full-text index has somehow become corrupt. It is an + error to attempt to rebuild the full-text index maintained by a contentless + FTS4 table. + + diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 67a0ea20..12013f2b 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -312,6 +312,11 @@ SQLITE_EXTENSION_INIT1 #endif +static int fts3EvalNext(Fts3Cursor *pCsr); +static int fts3EvalStart(Fts3Cursor *pCsr); +static int fts3TermSegReaderCursor( + Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); + /* ** Write a 64-bit variable-length integer to memory starting at p[0]. ** The length of data written will be between 1 and FTS3_VARINT_MAX bytes. @@ -433,7 +438,7 @@ static void fts3GetReverseVarint( sqlite3_int64 *pVal ){ sqlite3_int64 iVal; - char *p = *pp; + char *p; /* Pointer p now points at the first byte past the varint we are ** interested in. So, unless the doclist is corrupt, the 0x80 bit is @@ -463,6 +468,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){ sqlite3_free(p->zSegmentsTbl); sqlite3_free(p->zReadExprlist); sqlite3_free(p->zWriteExprlist); + sqlite3_free(p->zContentTbl); /* Invoke the tokenizer destructor to free the tokenizer. */ p->pTokenizer->pModule->xDestroy(p->pTokenizer); @@ -502,16 +508,19 @@ static void fts3DbExec( ** The xDestroy() virtual table method. */ static int fts3DestroyMethod(sqlite3_vtab *pVtab){ - int rc = SQLITE_OK; /* Return code */ Fts3Table *p = (Fts3Table *)pVtab; - sqlite3 *db = p->db; + int rc = SQLITE_OK; /* Return code */ + const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ + sqlite3 *db = p->db; /* Database handle */ /* Drop the shadow tables */ - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName); + if( p->zContentTbl==0 ){ + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName); + } + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName); + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName); + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName); + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName); /* If everything has worked, invoke fts3DisconnectMethod() to free the ** memory associated with the Fts3Table structure and return SQLITE_OK. @@ -573,23 +582,27 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){ static int fts3CreateTables(Fts3Table *p){ int rc = SQLITE_OK; /* Return code */ int i; /* Iterator variable */ - char *zContentCols; /* Columns of %_content table */ sqlite3 *db = p->db; /* The database connection */ - /* Create a list of user columns for the content table */ - zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); - for(i=0; zContentCols && inColumn; i++){ - char *z = p->azColumn[i]; - zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); - } - if( zContentCols==0 ) rc = SQLITE_NOMEM; + if( p->zContentTbl==0 ){ + char *zContentCols; /* Columns of %_content table */ + + /* Create a list of user columns for the content table */ + zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); + for(i=0; zContentCols && inColumn; i++){ + char *z = p->azColumn[i]; + zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); + } + if( zContentCols==0 ) rc = SQLITE_NOMEM; + + /* Create the content table */ + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_content'(%s)", + p->zDb, p->zName, zContentCols + ); + sqlite3_free(zContentCols); + } - /* Create the content table */ - fts3DbExec(&rc, db, - "CREATE TABLE %Q.'%q_content'(%s)", - p->zDb, p->zName, zContentCols - ); - sqlite3_free(zContentCols); /* Create other tables */ fts3DbExec(&rc, db, "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", @@ -740,8 +753,8 @@ static char *fts3QuoteId(char const *zInput){ } /* -** Return a list of comma separated SQL expressions that could be used -** in a SELECT statement such as the following: +** Return a list of comma separated SQL expressions and a FROM clause that +** could be used in a SELECT statement such as the following: ** ** SELECT FROM %_content AS x ... ** @@ -752,7 +765,7 @@ static char *fts3QuoteId(char const *zInput){ ** table has the three user-defined columns "a", "b", and "c", the following ** string is returned: ** -** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c')" +** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x" ** ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It ** is the responsibility of the caller to eventually free it. @@ -768,16 +781,28 @@ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){ char *zFunction; int i; - if( !zFunc ){ - zFunction = ""; + if( p->zContentTbl==0 ){ + if( !zFunc ){ + zFunction = ""; + }else{ + zFree = zFunction = fts3QuoteId(zFunc); + } + fts3Appendf(pRc, &zRet, "docid"); + for(i=0; inColumn; i++){ + fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); + } + sqlite3_free(zFree); }else{ - zFree = zFunction = fts3QuoteId(zFunc); + fts3Appendf(pRc, &zRet, "rowid"); + for(i=0; inColumn; i++){ + fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]); + } } - fts3Appendf(pRc, &zRet, "docid"); - for(i=0; inColumn; i++){ - fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); - } - sqlite3_free(zFree); + fts3Appendf(pRc, &zRet, "FROM '%q'.'%q%s' AS x", + p->zDb, + (p->zContentTbl ? p->zContentTbl : p->zName), + (p->zContentTbl ? "" : "_content") + ); return zRet; } @@ -820,9 +845,23 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){ return zRet; } +/* +** This function interprets the string at (*pp) as a non-negative integer +** value. It reads the integer and sets *pnOut to the value read, then +** sets *pp to point to the byte immediately following the last byte of +** the integer value. +** +** Only decimal digits ('0'..'9') may be part of an integer value. +** +** If *pp does not being with a decimal digit SQLITE_ERROR is returned and +** the output value undefined. Otherwise SQLITE_OK is returned. +** +** This function is used when parsing the "prefix=" FTS4 parameter. +*/ static int fts3GobbleInt(const char **pp, int *pnOut){ - const char *p = *pp; - int nInt = 0; + const char *p; /* Iterator pointer */ + int nInt = 0; /* Output value */ + for(p=*pp; p[0]>='0' && p[0]<='9'; p++){ nInt = nInt * 10 + (p[0] - '0'); } @@ -832,15 +871,30 @@ static int fts3GobbleInt(const char **pp, int *pnOut){ return SQLITE_OK; } - +/* +** This function is called to allocate an array of Fts3Index structures +** representing the indexes maintained by the current FTS table. FTS tables +** always maintain the main "terms" index, but may also maintain one or +** more "prefix" indexes, depending on the value of the "prefix=" parameter +** (if any) specified as part of the CREATE VIRTUAL TABLE statement. +** +** Argument zParam is passed the value of the "prefix=" option if one was +** specified, or NULL otherwise. +** +** If no error occurs, SQLITE_OK is returned and *apIndex set to point to +** the allocated array. *pnIndex is set to the number of elements in the +** array. If an error does occur, an SQLite error code is returned. +** +** Regardless of whether or not an error is returned, it is the responsibility +** of the caller to call sqlite3_free() on the output array to free it. +*/ static int fts3PrefixParameter( const char *zParam, /* ABC in prefix=ABC parameter to parse */ int *pnIndex, /* OUT: size of *apIndex[] array */ - struct Fts3Index **apIndex, /* OUT: Array of indexes for this table */ - struct Fts3Index **apFree /* OUT: Free this with sqlite3_free() */ + struct Fts3Index **apIndex /* OUT: Array of indexes for this table */ ){ - struct Fts3Index *aIndex; - int nIndex = 1; + struct Fts3Index *aIndex; /* Allocated array */ + int nIndex = 1; /* Number of entries in array */ if( zParam && zParam[0] ){ const char *p; @@ -851,7 +905,7 @@ static int fts3PrefixParameter( } aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex); - *apIndex = *apFree = aIndex; + *apIndex = aIndex; *pnIndex = nIndex; if( !aIndex ){ return SQLITE_NOMEM; @@ -872,6 +926,91 @@ static int fts3PrefixParameter( return SQLITE_OK; } +/* +** This function is called when initializing an FTS4 table that uses the +** content=xxx option. It determines the number of and names of the columns +** of the new FTS4 table. +** +** The third argument passed to this function is the value passed to the +** config=xxx option (i.e. "xxx"). This function queries the database for +** a table of that name. If found, the output variables are populated +** as follows: +** +** *pnCol: Set to the number of columns table xxx has, +** +** *pnStr: Set to the total amount of space required to store a copy +** of each columns name, including the nul-terminator. +** +** *pazCol: Set to point to an array of *pnCol strings. Each string is +** the name of the corresponding column in table xxx. The array +** and its contents are allocated using a single allocation. It +** is the responsibility of the caller to free this allocation +** by eventually passing the *pazCol value to sqlite3_free(). +** +** If the table cannot be found, an error code is returned and the output +** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is +** returned (and the output variables are undefined). +*/ +static int fts3ContentColumns( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */ + const char *zTbl, /* Name of content table */ + const char ***pazCol, /* OUT: Malloc'd array of column names */ + int *pnCol, /* OUT: Size of array *pazCol */ + int *pnStr /* OUT: Bytes of string content */ +){ + int rc = SQLITE_OK; /* Return code */ + char *zSql; /* "SELECT *" statement on zTbl */ + sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */ + + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + } + sqlite3_free(zSql); + + if( rc==SQLITE_OK ){ + const char **azCol; /* Output array */ + int nStr = 0; /* Size of all column names (incl. 0x00) */ + int nCol; /* Number of table columns */ + int i; /* Used to iterate through columns */ + + /* Loop through the returned columns. Set nStr to the number of bytes of + ** space required to store a copy of each column name, including the + ** nul-terminator byte. */ + nCol = sqlite3_column_count(pStmt); + for(i=0; i MATCHINFO */ - { "prefix", 6, 0 }, /* 1 -> PREFIX */ - { "compress", 8, 0 }, /* 2 -> COMPRESS */ - { "uncompress", 10, 0 }, /* 3 -> UNCOMPRESS */ - { "order", 5, 0 } /* 4 -> ORDER */ + { "matchinfo", 9 }, /* 0 -> MATCHINFO */ + { "prefix", 6 }, /* 1 -> PREFIX */ + { "compress", 8 }, /* 2 -> COMPRESS */ + { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ + { "order", 5 }, /* 4 -> ORDER */ + { "content", 7 } /* 5 -> CONTENT */ }; int iOpt; @@ -1012,13 +1151,20 @@ static int fts3InitVtab( case 4: /* ORDER */ if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) - && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 3)) + && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) ){ *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal); rc = SQLITE_ERROR; } bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); break; + + default: /* CONTENT */ + assert( iOpt==5 ); + sqlite3_free(zUncompress); + zContent = zVal; + zVal = 0; + break; } } sqlite3_free(zVal); @@ -1031,6 +1177,26 @@ static int fts3InitVtab( aCol[nCol++] = z; } } + + /* If a content=xxx option was specified, the following: + ** + ** 1. Ignore any compress= and uncompress= options. + ** + ** 2. If no column names were specified as part of the CREATE VIRTUAL + ** TABLE statement, use all columns from the content table. + */ + if( rc==SQLITE_OK && zContent ){ + sqlite3_free(zCompress); + sqlite3_free(zUncompress); + zCompress = 0; + zUncompress = 0; + if( nCol==0 ){ + sqlite3_free((void*)aCol); + aCol = 0; + rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString); + } + assert( rc!=SQLITE_OK || nCol>0 ); + } if( rc!=SQLITE_OK ) goto fts3_init_out; if( nCol==0 ){ @@ -1046,7 +1212,7 @@ static int fts3InitVtab( } assert( pTokenizer ); - rc = fts3PrefixParameter(zPrefix, &nIndex, &aIndex, &aFree); + rc = fts3PrefixParameter(zPrefix, &nIndex, &aIndex); if( rc==SQLITE_ERROR ){ assert( zPrefix ); *pzErr = sqlite3_mprintf("error parsing prefix parameter: %s", zPrefix); @@ -1075,6 +1241,8 @@ static int fts3InitVtab( p->bHasDocsize = (isFts4 && bNoDocsize==0); p->bHasStat = isFts4; p->bDescIdx = bDescIdx; + p->zContentTbl = zContent; + zContent = 0; TESTONLY( p->inTransaction = -1 ); TESTONLY( p->mxSavepoint = -1 ); @@ -1133,9 +1301,10 @@ static int fts3InitVtab( fts3_init_out: sqlite3_free(zPrefix); - sqlite3_free(aFree); + sqlite3_free(aIndex); sqlite3_free(zCompress); sqlite3_free(zUncompress); + sqlite3_free(zContent); sqlite3_free((void *)aCol); if( rc!=SQLITE_OK ){ if( p ){ @@ -1287,35 +1456,64 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ return SQLITE_OK; } +/* +** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then +** compose and prepare an SQL statement of the form: +** +** "SELECT FROM %_content WHERE rowid = ?" +** +** (or the equivalent for a content=xxx table) and set pCsr->pStmt to +** it. If an error occurs, return an SQLite error code. +** +** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK. +*/ +static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){ + int rc = SQLITE_OK; + if( pCsr->pStmt==0 ){ + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + char *zSql; + zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); + if( !zSql ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + sqlite3_free(zSql); + } + *ppStmt = pCsr->pStmt; + return rc; +} + /* ** 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){ + int rc = SQLITE_OK; if( pCsr->isRequireSeek ){ - sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); - pCsr->isRequireSeek = 0; - if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ - return SQLITE_OK; - }else{ - int rc = sqlite3_reset(pCsr->pStmt); - if( rc==SQLITE_OK ){ - /* If no row was found and no error has occured, then the %_content - ** table is missing a row that is present in the full-text index. - ** The data structures are corrupt. - */ - rc = SQLITE_CORRUPT_VTAB; + sqlite3_stmt *pStmt = 0; + + rc = fts3CursorSeekStmt(pCsr, &pStmt); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); + pCsr->isRequireSeek = 0; + if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ + return SQLITE_OK; + }else{ + rc = sqlite3_reset(pCsr->pStmt); + if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ + /* If no row was found and no error has occured, then the %_content + ** table is missing a row that is present in the full-text index. + ** The data structures are corrupt. */ + rc = FTS_CORRUPT_VTAB; + pCsr->isEof = 1; + } } - pCsr->isEof = 1; - if( pContext ){ - sqlite3_result_error_code(pContext, rc); - } - return rc; } - }else{ - return SQLITE_OK; } + + if( rc!=SQLITE_OK && pContext ){ + sqlite3_result_error_code(pContext, rc); + } + return rc; } /* @@ -1365,7 +1563,7 @@ static int fts3ScanInteriorNode( zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); if( zCsr>zEnd ){ - return SQLITE_CORRUPT_VTAB; + return FTS_CORRUPT_VTAB; } while( zCsrzEnd ){ - rc = SQLITE_CORRUPT_VTAB; + rc = FTS_CORRUPT_VTAB; goto finish_scan; } if( nPrefix+nSuffix>nAlloc ){ @@ -1396,6 +1594,7 @@ static int fts3ScanInteriorNode( } zBuffer = zNew; } + assert( zBuffer ); memcpy(&zBuffer[nPrefix], zCsr, nSuffix); nBuffer = nPrefix + nSuffix; zCsr += nSuffix; @@ -1724,8 +1923,6 @@ static void fts3PoslistMerge( } /* -** nToken==1 searches for adjacent positions. -** ** This function is used to merge two position lists into one. When it is ** called, *pp1 and *pp2 must both point to position lists. A position-list is ** the part of a doclist that follows each document id. For example, if a row @@ -1745,6 +1942,8 @@ static void fts3PoslistMerge( ** *pp1 so that (pos(*pp2)>pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e. ** when the *pp1 token appears before the *pp2 token, but not more than nToken ** slots before it. +** +** e.g. nToken==1 searches for adjacent positions. */ static int fts3PoslistPhraseMerge( char **pp, /* IN/OUT: Preallocated output buffer */ @@ -1754,7 +1953,7 @@ static int fts3PoslistPhraseMerge( char **pp1, /* IN/OUT: Left input list */ char **pp2 /* IN/OUT: Right input list */ ){ - char *p = (pp ? *pp : 0); + char *p = *pp; char *p1 = *pp1; char *p2 = *pp2; int iCol1 = 0; @@ -1763,7 +1962,7 @@ static int fts3PoslistPhraseMerge( /* Never set both isSaveLeft and isExact for the same invocation. */ assert( isSaveLeft==0 || isExact==0 ); - assert( *p1!=0 && *p2!=0 ); + assert( p!=0 && *p1!=0 && *p2!=0 ); if( *p1==POS_COLUMN ){ p1++; p1 += sqlite3Fts3GetVarint32(p1, &iCol1); @@ -1780,7 +1979,7 @@ static int fts3PoslistPhraseMerge( sqlite3_int64 iPos1 = 0; sqlite3_int64 iPos2 = 0; - if( pp && iCol1 ){ + if( iCol1 ){ *p++ = POS_COLUMN; p += sqlite3Fts3PutVarint(p, iCol1); } @@ -1795,16 +1994,10 @@ static int fts3PoslistPhraseMerge( || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) ){ sqlite3_int64 iSave; - if( !pp ){ - fts3PoslistCopy(0, &p2); - fts3PoslistCopy(0, &p1); - *pp1 = p1; - *pp2 = p2; - return 1; - } iSave = isSaveLeft ? iPos1 : iPos2; fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; pSave = 0; + assert( p ); } if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ if( (*p2&0xFE)==0 ) break; @@ -1853,7 +2046,7 @@ static int fts3PoslistPhraseMerge( fts3PoslistCopy(0, &p1); *pp1 = p1; *pp2 = p2; - if( !pp || *pp==p ){ + if( *pp==p ){ return 0; } *p++ = 0x00; @@ -1911,22 +2104,34 @@ static int fts3PoslistNearMerge( } /* -** A pointer to an instance of this structure is used as the context -** argument to sqlite3Fts3SegReaderIterate() +** An instance of this function is used to merge together the (potentially +** large number of) doclists for each term that matches a prefix query. +** See function fts3TermSelectMerge() for details. */ typedef struct TermSelect TermSelect; struct TermSelect { - int isReqPos; - char *aaOutput[16]; /* Malloc'd output buffer */ - int anOutput[16]; /* Size of output in bytes */ + char *aaOutput[16]; /* Malloc'd output buffers */ + int anOutput[16]; /* Size each output buffer in bytes */ }; - +/* +** This function is used to read a single varint from a buffer. Parameter +** pEnd points 1 byte past the end of the buffer. When this function is +** called, if *pp points to pEnd or greater, then the end of the buffer +** has been reached. In this case *pp is set to 0 and the function returns. +** +** If *pp does not point to or past pEnd, then a single varint is read +** from *pp. *pp is then set to point 1 byte past the end of the read varint. +** +** If bDescIdx is false, the value read is added to *pVal before returning. +** If it is true, the value read is subtracted from *pVal before this +** function returns. +*/ static void fts3GetDeltaVarint3( - char **pp, - char *pEnd, - int bDescIdx, - sqlite3_int64 *pVal + char **pp, /* IN/OUT: Point to read varint from */ + char *pEnd, /* End of buffer */ + int bDescIdx, /* True if docids are descending */ + sqlite3_int64 *pVal /* IN/OUT: Integer value */ ){ if( *pp>=pEnd ){ *pp = 0; @@ -1941,6 +2146,21 @@ static void fts3GetDeltaVarint3( } } +/* +** This function is used to write a single varint to a buffer. The varint +** is written to *pp. Before returning, *pp is set to point 1 byte past the +** end of the value written. +** +** If *pbFirst is zero when this function is called, the value written to +** the buffer is that of parameter iVal. +** +** If *pbFirst is non-zero when this function is called, then the value +** written is either (iVal-*piPrev) (if bDescIdx is zero) or (*piPrev-iVal) +** (if bDescIdx is non-zero). +** +** Before returning, this function always sets *pbFirst to 1 and *piPrev +** to the value of parameter iVal. +*/ static void fts3PutDeltaVarint3( char **pp, /* IN/OUT: Output pointer */ int bDescIdx, /* True for descending docids */ @@ -1961,10 +2181,34 @@ static void fts3PutDeltaVarint3( *pbFirst = 1; } -#define COMPARE_DOCID(i1, i2) ((bDescIdx?-1:1) * (i1-i2)) +/* +** This macro is used by various functions that merge doclists. The two +** arguments are 64-bit docid values. If the value of the stack variable +** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). +** Otherwise, (i2-i1). +** +** Using this makes it easier to write code that can merge doclists that are +** sorted in either ascending or descending order. +*/ +#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2)) + +/* +** This function does an "OR" merge of two doclists (output contains all +** positions contained in either argument doclist). If the docids in the +** input doclists are sorted in ascending order, parameter bDescDoclist +** should be false. If they are sorted in ascending order, it should be +** passed a non-zero value. +** +** If no error occurs, *paOut is set to point at an sqlite3_malloc'd buffer +** containing the output doclist and SQLITE_OK is returned. In this case +** *pnOut is set to the number of bytes in the output doclist. +** +** If an error occurs, an SQLite error code is returned. The output values +** are undefined in this case. +*/ static int fts3DoclistOrMerge( - int bDescIdx, /* True if arguments are desc */ + int bDescDoclist, /* True if arguments are desc */ char *a1, int n1, /* First doclist */ char *a2, int n2, /* Second doclist */ char **paOut, int *pnOut /* OUT: Malloc'd doclist */ @@ -1982,38 +2226,81 @@ static int fts3DoclistOrMerge( *paOut = 0; *pnOut = 0; - aOut = sqlite3_malloc(n1+n2); + + /* Allocate space for the output. Both the input and output doclists + ** are delta encoded. If they are in ascending order (bDescDoclist==0), + ** then the first docid in each list is simply encoded as a varint. For + ** each subsequent docid, the varint stored is the difference between the + ** current and previous docid (a positive number - since the list is in + ** ascending order). + ** + ** The first docid written to the output is therefore encoded using the + ** same number of bytes as it is in whichever of the input lists it is + ** read from. And each subsequent docid read from the same input list + ** consumes either the same or less bytes as it did in the input (since + ** the difference between it and the previous value in the output must + ** be a positive value less than or equal to the delta value read from + ** the input list). The same argument applies to all but the first docid + ** read from the 'other' list. And to the contents of all position lists + ** that will be copied and merged from the input to the output. + ** + ** However, if the first docid copied to the output is a negative number, + ** then the encoding of the first docid from the 'other' input list may + ** be larger in the output than it was in the input (since the delta value + ** may be a larger positive integer than the actual docid). + ** + ** The space required to store the output is therefore the sum of the + ** sizes of the two inputs, plus enough space for exactly one of the input + ** docids to grow. + ** + ** A symetric argument may be made if the doclists are in descending + ** order. + */ + aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1); if( !aOut ) return SQLITE_NOMEM; p = aOut; fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); while( p1 || p2 ){ - sqlite3_int64 iDiff = COMPARE_DOCID(i1, i2); + sqlite3_int64 iDiff = DOCID_CMP(i1, i2); if( p2 && p1 && iDiff==0 ){ - fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i1); + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); fts3PoslistMerge(&p, &p1, &p2); - fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1); - fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); }else if( !p2 || (p1 && iDiff<0) ){ - fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i1); + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); fts3PoslistCopy(&p, &p1); - fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); }else{ - fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i2); + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2); fts3PoslistCopy(&p, &p2); - fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); } } *paOut = aOut; *pnOut = (p-aOut); + assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 ); return SQLITE_OK; } +/* +** This function does a "phrase" merge of two doclists. In a phrase merge, +** the output contains a copy of each position from the right-hand input +** doclist for which there is a position in the left-hand input doclist +** exactly nDist tokens before it. +** +** If the docids in the input doclists are sorted in ascending order, +** parameter bDescDoclist should be false. If they are sorted in ascending +** order, it should be passed a non-zero value. +** +** The right-hand input doclist is overwritten by this function. +*/ static void fts3DoclistPhraseMerge( - int bDescIdx, /* True if arguments are desc */ + int bDescDoclist, /* True if arguments are desc */ int nDist, /* Distance from left to right (1=adjacent) */ char *aLeft, int nLeft, /* Left doclist */ char *aRight, int *pnRight /* IN/OUT: Right/output doclist */ @@ -2036,32 +2323,82 @@ static void fts3DoclistPhraseMerge( fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); while( p1 && p2 ){ - sqlite3_int64 iDiff = COMPARE_DOCID(i1, i2); + sqlite3_int64 iDiff = DOCID_CMP(i1, i2); if( iDiff==0 ){ char *pSave = p; sqlite3_int64 iPrevSave = iPrev; int bFirstOutSave = bFirstOut; - fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i1); + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); if( 0==fts3PoslistPhraseMerge(&p, nDist, 0, 1, &p1, &p2) ){ p = pSave; iPrev = iPrevSave; bFirstOut = bFirstOutSave; } - fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1); - fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); }else if( iDiff<0 ){ fts3PoslistCopy(0, &p1); - fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); }else{ fts3PoslistCopy(0, &p2); - fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); } } *pnRight = p - aOut; } +/* +** Argument pList points to a position list nList bytes in size. This +** function checks to see if the position list contains any entries for +** a token in position 0 (of any column). If so, it writes argument iDelta +** to the output buffer pOut, followed by a position list consisting only +** of the entries from pList at position 0, and terminated by an 0x00 byte. +** The value returned is the number of bytes written to pOut (if any). +*/ +int sqlite3Fts3FirstFilter( + sqlite3_int64 iDelta, /* Varint that may be written to pOut */ + char *pList, /* Position list (no 0x00 term) */ + int nList, /* Size of pList in bytes */ + char *pOut /* Write output here */ +){ + int nOut = 0; + int bWritten = 0; /* True once iDelta has been written */ + char *p = pList; + char *pEnd = &pList[nList]; + + if( *p!=0x01 ){ + if( *p==0x02 ){ + nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); + pOut[nOut++] = 0x02; + bWritten = 1; + } + fts3ColumnlistCopy(0, &p); + } + + while( paaOutput[0]==0 ){ /* If this is the first term selected, copy the doclist to the output ** buffer using memcpy(). */ @@ -2201,6 +2539,13 @@ static int fts3SegReaderCursorAppend( return SQLITE_OK; } +/* +** Add seg-reader objects to the Fts3MultiSegReader object passed as the +** 8th argument. +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ static int fts3SegReaderCursor( Fts3Table *p, /* FTS3 table handle */ int iIndex, /* Index to search (from 0 to p->nIndex-1) */ @@ -2209,11 +2554,11 @@ static int fts3SegReaderCursor( int nTerm, /* Size of zTerm in bytes */ int isPrefix, /* True for a prefix search */ int isScan, /* True to scan from zTerm to EOF */ - Fts3MultiSegReader *pCsr /* Cursor object to populate */ + Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ - int rc = SQLITE_OK; - int rc2; - sqlite3_stmt *pStmt = 0; + int rc = SQLITE_OK; /* Error code */ + sqlite3_stmt *pStmt = 0; /* Statement to iterate through segments */ + int rc2; /* Result of sqlite3_reset() */ /* If iLevel is less than 0 and this is not a scan, include a seg-reader ** for the pending-terms. If this is a scan, then this call must be being @@ -2302,24 +2647,42 @@ int sqlite3Fts3SegReaderCursor( ); } +/* +** In addition to its current configuration, have the Fts3MultiSegReader +** passed as the 4th argument also scan the doclist for term zTerm/nTerm. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +*/ static int fts3SegReaderCursorAddZero( - Fts3Table *p, - const char *zTerm, - int nTerm, - Fts3MultiSegReader *pCsr + Fts3Table *p, /* FTS virtual table handle */ + const char *zTerm, /* Term to scan doclist of */ + int nTerm, /* Number of bytes in zTerm */ + Fts3MultiSegReader *pCsr /* Fts3MultiSegReader to modify */ ){ return fts3SegReaderCursor(p, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0,pCsr); } - -int sqlite3Fts3TermSegReaderCursor( +/* +** Open an Fts3MultiSegReader to scan the doclist for term zTerm/nTerm. Or, +** if isPrefix is true, to scan the doclist for all terms for which +** zTerm/nTerm is a prefix. If successful, return SQLITE_OK and write +** a pointer to the new Fts3MultiSegReader to *ppSegcsr. Otherwise, return +** an SQLite error code. +** +** It is the responsibility of the caller to free this object by eventually +** passing it to fts3SegReaderCursorFree() +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +** Output parameter *ppSegcsr is set to 0 if an error occurs. +*/ +static int fts3TermSegReaderCursor( Fts3Cursor *pCsr, /* Virtual table cursor handle */ const char *zTerm, /* Term to query for */ int nTerm, /* Size of zTerm in bytes */ int isPrefix, /* True for a prefix search */ Fts3MultiSegReader **ppSegcsr /* OUT: Allocated seg-reader cursor */ ){ - Fts3MultiSegReader *pSegcsr; /* Object to allocate and return */ + Fts3MultiSegReader *pSegcsr; /* Object to allocate and return */ int rc = SQLITE_NOMEM; /* Return code */ pSegcsr = sqlite3_malloc(sizeof(Fts3MultiSegReader)); @@ -2363,6 +2726,9 @@ int sqlite3Fts3TermSegReaderCursor( return rc; } +/* +** Free an Fts3MultiSegReader allocated by fts3TermSegReaderCursor(). +*/ static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ sqlite3Fts3SegReaderFinish(pSegcsr); sqlite3_free(pSegcsr); @@ -2370,35 +2736,26 @@ static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ /* ** This function retreives the doclist for the specified term (or term -** prefix) from the database. -** -** 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 (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. +** prefix) from the database. */ static int fts3TermSelect( Fts3Table *p, /* Virtual table handle */ Fts3PhraseToken *pTok, /* Token to query for */ int iColumn, /* Column to query (or -ve for all columns) */ - int isReqPos, /* True to include position lists in output */ int *pnOut, /* OUT: Size of buffer at *ppOut */ char **ppOut /* OUT: Malloced result buffer */ ){ int rc; /* Return code */ - Fts3MultiSegReader *pSegcsr; /* Seg-reader cursor for this term */ - TermSelect tsc; /* Context object for fts3TermSelectCb() */ + Fts3MultiSegReader *pSegcsr; /* Seg-reader cursor for this term */ + TermSelect tsc; /* Object for pair-wise doclist merging */ Fts3SegFilter filter; /* Segment term filter configuration */ pSegcsr = pTok->pSegcsr; memset(&tsc, 0, sizeof(TermSelect)); - tsc.isReqPos = isReqPos; - filter.flags = FTS3_SEGMENT_IGNORE_EMPTY + filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) - | (isReqPos ? FTS3_SEGMENT_REQUIRE_POS : 0) + | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0) | (iColumnnColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); filter.iCol = iColumn; filter.zTerm = pTok->z; @@ -2408,13 +2765,11 @@ static int fts3TermSelect( while( SQLITE_OK==rc && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr)) ){ - rc = fts3TermSelectCb(p, (void *)&tsc, - pSegcsr->zTerm, pSegcsr->nTerm, pSegcsr->aDoclist, pSegcsr->nDoclist - ); + rc = fts3TermSelectMerge(p, &tsc, pSegcsr->aDoclist, pSegcsr->nDoclist); } if( rc==SQLITE_OK ){ - rc = fts3TermSelectMerge(p, &tsc); + rc = fts3TermSelectFinishMerge(p, &tsc); } if( rc==SQLITE_OK ){ *ppOut = tsc.aaOutput[0]; @@ -2440,24 +2795,15 @@ static int fts3TermSelect( ** that the doclist is simply a list of docids stored as delta encoded ** varints. */ -static int fts3DoclistCountDocids(int isPoslist, char *aList, int nList){ +static int fts3DoclistCountDocids(char *aList, int nList){ int nDoc = 0; /* Return value */ if( aList ){ char *aEnd = &aList[nList]; /* Pointer to one byte after EOF */ char *p = aList; /* Cursor */ - if( !isPoslist ){ - /* The number of docids in the list is the same as the number of - ** varints. In FTS3 a varint consists of a single byte with the 0x80 - ** bit cleared and zero or more bytes with the 0x80 bit set. So to - ** count the varints in the buffer, just count the number of bytes - ** with the 0x80 bit clear. */ - while( pbase.pVtab)->pSegments==0 ); return rc; @@ -2550,8 +2896,8 @@ static int fts3FilterMethod( return SQLITE_NOMEM; } - rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn, - iCol, zQuery, -1, &pCsr->pExpr + rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->bHasStat, + p->nColumn, iCol, zQuery, -1, &pCsr->pExpr ); if( rc!=SQLITE_OK ){ if( rc==SQLITE_ERROR ){ @@ -2564,7 +2910,7 @@ static int fts3FilterMethod( rc = sqlite3Fts3ReadLock(p); if( rc!=SQLITE_OK ) return rc; - rc = sqlite3Fts3EvalStart(pCsr, pCsr->pExpr, 1); + rc = fts3EvalStart(pCsr); sqlite3Fts3SegmentsClose(p); if( rc!=SQLITE_OK ) return rc; @@ -2578,23 +2924,24 @@ static int fts3FilterMethod( ** row by docid. */ if( idxNum==FTS3_FULLSCAN_SEARCH ){ - const char *zSort = (pCsr->bDesc ? "DESC" : "ASC"); - const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s"; - zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName, zSort); - }else{ - const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?"; - zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName); + zSql = sqlite3_mprintf( + "SELECT %s ORDER BY rowid %s", + p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") + ); + if( zSql ){ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + }else if( idxNum==FTS3_DOCID_SEARCH ){ + rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt); + if( rc==SQLITE_OK ){ + rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); + } } - if( !zSql ) return SQLITE_NOMEM; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); - sqlite3_free(zSql); if( rc!=SQLITE_OK ) return rc; - if( idxNum==FTS3_DOCID_SEARCH ){ - rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); - if( rc!=SQLITE_OK ) return rc; - } - return fts3NextMethod(pCursor); } @@ -2646,7 +2993,7 @@ static int fts3ColumnMethod( sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT); }else{ rc = fts3CursorSeek(0, pCsr); - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){ sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1)); } } @@ -2730,7 +3077,7 @@ static int fts3RollbackMethod(sqlite3_vtab *pVtab){ */ static void fts3ReversePoslist(char *pStart, char **ppPoslist){ char *p = &(*ppPoslist)[-2]; - char c; + char c = 0; while( p>pStart && (c=*p--)==0 ); while( p>pStart && (*p & 0x80) | c ){ @@ -2939,15 +3286,22 @@ static int fts3RenameMethod( sqlite3 *db = p->db; /* Database connection */ int rc; /* Return Code */ + /* As it happens, the pending terms table is always empty here. This is + ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction + ** always opens a savepoint transaction. And the xSavepoint() method + ** flushes the pending terms table. But leave the (no-op) call to + ** PendingTermsFlush() in in case that changes. + */ + assert( p->nPendingData==0 ); rc = sqlite3Fts3PendingTermsFlush(p); - if( rc!=SQLITE_OK ){ - return rc; + + if( p->zContentTbl==0 ){ + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", + p->zDb, p->zName, zName + ); } - fts3DbExec(&rc, db, - "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", - p->zDb, p->zName, zName - ); if( p->bHasDocsize ){ fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", @@ -2971,6 +3325,11 @@ static int fts3RenameMethod( return rc; } +/* +** The xSavepoint() method. +** +** Flush the contents of the pending-terms table to disk. +*/ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ UNUSED_PARAMETER(iSavepoint); assert( ((Fts3Table *)pVtab)->inTransaction ); @@ -2978,6 +3337,12 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint ); return fts3SyncMethod(pVtab); } + +/* +** The xRelease() method. +** +** This is a no-op. +*/ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); UNUSED_PARAMETER(iSavepoint); @@ -2987,6 +3352,12 @@ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ TESTONLY( p->mxSavepoint = iSavepoint-1 ); return SQLITE_OK; } + +/* +** The xRollbackTo() method. +** +** Discard the contents of the pending terms table. +*/ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts3Table *p = (Fts3Table*)pVtab; UNUSED_PARAMETER(iSavepoint); @@ -3136,18 +3507,6 @@ int sqlite3Fts3Init(sqlite3 *db){ return rc; } -#if !SQLITE_CORE -int sqlite3_extension_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - SQLITE_EXTENSION_INIT2(pApi) - return sqlite3Fts3Init(db); -} -#endif - - /* ** Allocate an Fts3MultiSegReader for each token in the expression headed ** by pExpr. @@ -3164,11 +3523,11 @@ int sqlite3_extension_init( ** doclist and then traversed. */ static void fts3EvalAllocateReaders( - Fts3Cursor *pCsr, - Fts3Expr *pExpr, + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Allocate readers for this expression */ int *pnToken, /* OUT: Total number of tokens in phrase. */ int *pnOr, /* OUT: Total number of OR nodes in expr. */ - int *pRc + int *pRc /* IN/OUT: Error code */ ){ if( pExpr && SQLITE_OK==*pRc ){ if( pExpr->eType==FTSQUERY_PHRASE ){ @@ -3177,7 +3536,7 @@ static void fts3EvalAllocateReaders( *pnToken += nToken; for(i=0; ipPhrase->aToken[i]; - int rc = sqlite3Fts3TermSegReaderCursor(pCsr, + int rc = fts3TermSegReaderCursor(pCsr, pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr ); if( rc!=SQLITE_OK ){ @@ -3195,12 +3554,20 @@ static void fts3EvalAllocateReaders( } } +/* +** Arguments pList/nList contain the doclist for token iToken of phrase p. +** It is merged into the main doclist stored in p->doclist.aAll/nAll. +** +** This function assumes that pList points to a buffer allocated using +** sqlite3_malloc(). This function takes responsibility for eventually +** freeing the buffer. +*/ static void fts3EvalPhraseMergeToken( - Fts3Table *pTab, - Fts3Phrase *p, - int iToken, - char *pList, - int nList + Fts3Table *pTab, /* FTS Table pointer */ + Fts3Phrase *p, /* Phrase to merge pList/nList into */ + int iToken, /* Token pList/nList corresponds to */ + char *pList, /* Pointer to doclist */ + int nList /* Number of bytes in pList */ ){ assert( iToken!=p->iDoclistToken ); @@ -3249,9 +3616,15 @@ static void fts3EvalPhraseMergeToken( if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken; } +/* +** Load the doclist for phrase p into p->doclist.aAll/nAll. The loaded doclist +** does not take deferred tokens into account. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +*/ static int fts3EvalPhraseLoad( - Fts3Cursor *pCsr, - Fts3Phrase *p + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p /* Phrase object */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int iToken; @@ -3264,7 +3637,7 @@ static int fts3EvalPhraseLoad( if( pToken->pSegcsr ){ int nThis = 0; char *pThis = 0; - rc = fts3TermSelect(pTab, pToken, p->iColumn, 1, &nThis, &pThis); + rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis); if( rc==SQLITE_OK ){ fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis); } @@ -3275,25 +3648,32 @@ static int fts3EvalPhraseLoad( return rc; } +/* +** This function is called on each phrase after the position lists for +** any deferred tokens have been loaded into memory. It updates the phrases +** current position list to include only those positions that are really +** instances of the phrase (after considering deferred tokens). If this +** means that the phrase does not appear in the current row, doclist.pList +** and doclist.nList are both zeroed. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +*/ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ - int iToken; - int rc = SQLITE_OK; - - int nMaxUndeferred = pPhrase->iDoclistToken; - char *aPoslist = 0; - int nPoslist = 0; - int iPrev = -1; + int iToken; /* Used to iterate through phrase tokens */ + char *aPoslist = 0; /* Position list for deferred tokens */ + int nPoslist = 0; /* Number of bytes in aPoslist */ + int iPrev = -1; /* Token number of previous deferred token */ assert( pPhrase->doclist.bFreeList==0 ); - for(iToken=0; rc==SQLITE_OK && iTokennToken; iToken++){ + for(iToken=0; iTokennToken; iToken++){ Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; Fts3DeferredToken *pDeferred = pToken->pDeferred; if( pDeferred ){ char *pList; int nList; - rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); + int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); if( rc!=SQLITE_OK ) return rc; if( pList==0 ){ @@ -3328,6 +3708,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ } if( iPrev>=0 ){ + int nMaxUndeferred = pPhrase->iDoclistToken; if( nMaxUndeferred<0 ){ pPhrase->doclist.pList = aPoslist; pPhrase->doclist.nList = nPoslist; @@ -3376,9 +3757,15 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ ** expression to initialize the mechanism for returning rows. Once this ** function has been called successfully on an Fts3Phrase, it may be ** used with fts3EvalPhraseNext() to iterate through the matching docids. +** +** If parameter bOptOk is true, then the phrase may (or may not) use the +** incremental loading strategy. Otherwise, the entire doclist is loaded into +** memory within this call. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ - int rc; + int rc; /* Error code */ Fts3PhraseToken *pFirst = &p->aToken[0]; Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; @@ -3387,6 +3774,7 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ && p->nToken==1 && pFirst->pSegcsr && pFirst->pSegcsr->bLookup + && pFirst->bFirst==0 ){ /* Use the incremental approach. */ int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); @@ -3406,7 +3794,13 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ /* ** This function is used to iterate backwards (from the end to start) -** through doclists. +** through doclists. It is used by this module to iterate through phrase +** doclists in reverse and by the fts3_write.c module to iterate through +** pending-terms lists when writing to databases with "order=desc". +** +** The doclist may be sorted in ascending (parameter bDescIdx==0) or +** descending (parameter bDescIdx==1) order of docid. Regardless, this +** function iterates from the end of the doclist to the beginning. */ void sqlite3Fts3DoclistPrev( int bDescIdx, /* True if the doclist is desc */ @@ -3471,9 +3865,9 @@ void sqlite3Fts3DoclistPrev( ** successfully advanced, *pbEof is set to 0. */ static int fts3EvalPhraseNext( - Fts3Cursor *pCsr, - Fts3Phrase *p, - u8 *pbEof + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p, /* Phrase object to advance to next docid */ + u8 *pbEof /* OUT: Set to 1 if EOF */ ){ int rc = SQLITE_OK; Fts3Doclist *pDL = &p->doclist; @@ -3519,10 +3913,10 @@ static int fts3EvalPhraseNext( /* pIter now points just past the 0x00 that terminates the position- ** list for document pDL->iDocid. However, if this position-list was - ** edited in place by fts3EvalNearTrim2(), then pIter may not actually + ** edited in place by fts3EvalNearTrim(), then pIter may not actually ** point to the start of the next docid value. The following line deals ** with this case by advancing pIter past the zero-padding added by - ** fts3EvalNearTrim2(). */ + ** fts3EvalNearTrim(). */ while( pIterpNextDocid = pIter; @@ -3534,11 +3928,27 @@ static int fts3EvalPhraseNext( return rc; } +/* +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, fts3EvalPhraseStart() is called on all phrases within the +** expression. Also the Fts3Expr.bDeferred variable is set to true for any +** expressions for which all descendent tokens are deferred. +** +** If parameter bOptOk is zero, then it is guaranteed that the +** Fts3Phrase.doclist.aAll/nAll variables contain the entire doclist for +** each phrase in the expression (subject to deferred token processing). +** Or, if bOptOk is non-zero, then one or more tokens within the expression +** may be loaded incrementally, meaning doclist.aAll/nAll is not available. +** +** If an error occurs within this function, *pRc is set to an SQLite error +** code before returning. +*/ static void fts3EvalStartReaders( - Fts3Cursor *pCsr, - Fts3Expr *pExpr, - int bOptOk, - int *pRc + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pExpr, /* Expression to initialize phrases in */ + int bOptOk, /* True to enable incremental loading */ + int *pRc /* IN/OUT: Error code */ ){ if( pExpr && SQLITE_OK==*pRc ){ if( pExpr->eType==FTSQUERY_PHRASE ){ @@ -3557,25 +3967,44 @@ static void fts3EvalStartReaders( } } +/* +** An array of the following structures is assembled as part of the process +** of selecting tokens to defer before the query starts executing (as part +** of the xFilter() method). There is one element in the array for each +** token in the FTS expression. +** +** Tokens are divided into AND/NEAR clusters. All tokens in a cluster belong +** to phrases that are connected only by AND and NEAR operators (not OR or +** NOT). When determining tokens to defer, each AND/NEAR cluster is considered +** separately. The root of a tokens AND/NEAR cluster is stored in +** Fts3TokenAndCost.pRoot. +*/ typedef struct Fts3TokenAndCost Fts3TokenAndCost; struct Fts3TokenAndCost { Fts3Phrase *pPhrase; /* The phrase the token belongs to */ int iToken; /* Position of token in phrase */ Fts3PhraseToken *pToken; /* The token itself */ - Fts3Expr *pRoot; - int nOvfl; + Fts3Expr *pRoot; /* Root of NEAR/AND cluster */ + int nOvfl; /* Number of overflow pages to load doclist */ int iCol; /* The column the token must match */ }; +/* +** This function is used to populate an allocated Fts3TokenAndCost array. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, if an error occurs during execution, *pRc is set to an +** SQLite error code. +*/ static void fts3EvalTokenCosts( - Fts3Cursor *pCsr, - Fts3Expr *pRoot, - Fts3Expr *pExpr, - Fts3TokenAndCost **ppTC, - Fts3Expr ***ppOr, - int *pRc + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pRoot, /* Root of current AND/NEAR cluster */ + Fts3Expr *pExpr, /* Expression to consider */ + Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ + Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ + int *pRc /* IN/OUT: Error code */ ){ - if( *pRc==SQLITE_OK && pExpr ){ + if( *pRc==SQLITE_OK ){ if( pExpr->eType==FTSQUERY_PHRASE ){ Fts3Phrase *pPhrase = pExpr->pPhrase; int i; @@ -3589,6 +4018,11 @@ static void fts3EvalTokenCosts( *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); } }else if( pExpr->eType!=FTSQUERY_NOT ){ + assert( pExpr->eType==FTSQUERY_OR + || pExpr->eType==FTSQUERY_AND + || pExpr->eType==FTSQUERY_NEAR + ); + assert( pExpr->pLeft && pExpr->pRight ); if( pExpr->eType==FTSQUERY_OR ){ pRoot = pExpr->pLeft; **ppOr = pRoot; @@ -3605,19 +4039,30 @@ static void fts3EvalTokenCosts( } } +/* +** Determine the average document (row) size in pages. If successful, +** write this value to *pnPage and return SQLITE_OK. Otherwise, return +** an SQLite error code. +** +** The average document size in pages is calculated by first calculating +** determining the average size in bytes, B. If B is less than the amount +** of data that will fit on a single leaf page of an intkey table in +** this database, then the average docsize is 1. Otherwise, it is 1 plus +** the number of overflow pages consumed by a record B bytes in size. +*/ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ if( pCsr->nRowAvg==0 ){ /* The average document size, which is required to calculate the cost - ** of each doclist, has not yet been determined. Read the required - ** data from the %_stat table to calculate it. - ** - ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 - ** varints, where nCol is the number of columns in the FTS3 table. - ** The first varint is the number of documents currently stored in - ** the table. The following nCol varints contain the total amount of - ** data stored in all rows of each column of the table, from left - ** to right. - */ + ** of each doclist, has not yet been determined. Read the required + ** data from the %_stat table to calculate it. + ** + ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 + ** varints, where nCol is the number of columns in the FTS3 table. + ** The first varint is the number of documents currently stored in + ** the table. The following nCol varints contain the total amount of + ** data stored in all rows of each column of the table, from left + ** to right. + */ int rc; Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; sqlite3_stmt *pStmt; @@ -3638,7 +4083,7 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ } if( nDoc==0 || nByte==0 ){ sqlite3_reset(pStmt); - return SQLITE_CORRUPT_VTAB; + return FTS_CORRUPT_VTAB; } pCsr->nDoc = nDoc; @@ -3652,68 +4097,130 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ return SQLITE_OK; } +/* +** This function is called to select the tokens (if any) that will be +** deferred. The array aTC[] has already been populated when this is +** called. +** +** This function is called once for each AND/NEAR cluster in the +** expression. Each invocation determines which tokens to defer within +** the cluster with root node pRoot. See comments above the definition +** of struct Fts3TokenAndCost for more details. +** +** If no error occurs, SQLITE_OK is returned and sqlite3Fts3DeferToken() +** called on each token to defer. Otherwise, an SQLite error code is +** returned. +*/ static int fts3EvalSelectDeferred( - Fts3Cursor *pCsr, - Fts3Expr *pRoot, - Fts3TokenAndCost *aTC, - int nTC + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pRoot, /* Consider tokens with this root node */ + Fts3TokenAndCost *aTC, /* Array of expression tokens and costs */ + int nTC /* Number of entries in aTC[] */ ){ - int nDocSize = 0; - int nDocEst = 0; - int rc = SQLITE_OK; Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int ii; + int nDocSize = 0; /* Number of pages per doc loaded */ + int rc = SQLITE_OK; /* Return code */ + int ii; /* Iterator variable for various purposes */ + int nOvfl = 0; /* Total overflow pages used by doclists */ + int nToken = 0; /* Total number of tokens in cluster */ - int nOvfl = 0; - int nTerm = 0; + int nMinEst = 0; /* The minimum count for any phrase so far. */ + int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ + /* Tokens are never deferred for FTS tables created using the content=xxx + ** option. The reason being that it is not guaranteed that the content + ** table actually contains the same data as the index. To prevent this from + ** causing any problems, the deferred token optimization is completely + ** disabled for content=xxx tables. */ + if( pTab->zContentTbl ){ + return SQLITE_OK; + } + + /* Count the tokens in this AND/NEAR cluster. If none of the doclists + ** associated with the tokens spill onto overflow pages, or if there is + ** only 1 token, exit early. No tokens to defer in this case. */ for(ii=0; ii0 ); - for(ii=0; iinOvfl) + /* Iterate through all tokens in this AND/NEAR cluster, in ascending order + ** of the number of overflow pages that will be loaded by the pager layer + ** to retrieve the entire doclist for the token from the full-text index. + ** Load the doclists for tokens that are either: + ** + ** a. The cheapest token in the entire query (i.e. the one visited by the + ** first iteration of this loop), or + ** + ** b. Part of a multi-token phrase. + ** + ** After each token doclist is loaded, merge it with the others from the + ** same phrase and count the number of documents that the merged doclist + ** contains. Set variable "nMinEst" to the smallest number of documents in + ** any phrase doclist for which 1 or more token doclists have been loaded. + ** Let nOther be the number of other phrases for which it is certain that + ** one or more tokens will not be deferred. + ** + ** Then, for each token, defer it if loading the doclist would result in + ** loading N or more overflow pages into memory, where N is computed as: + ** + ** (nMinEst + 4^nOther - 1) / (4^nOther) + */ + for(ii=0; iinOvfl) ){ - pTC = &aTC[jj]; + pTC = &aTC[iTC]; } } assert( pTC ); - /* At this point pTC points to the cheapest remaining token. */ - if( ii==0 ){ - if( pTC->nOvfl ){ - nDocEst = (pTC->nOvfl * pTab->nPgsz + pTab->nPgsz) / 10; - }else{ + if( ii && pTC->nOvfl>=((nMinEst+(nLoad4/4)-1)/(nLoad4/4))*nDocSize ){ + /* The number of overflow pages to load for this (and therefore all + ** subsequent) tokens is greater than the estimated number of pages + ** that will be loaded if all subsequent tokens are deferred. + */ + Fts3PhraseToken *pToken = pTC->pToken; + rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); + fts3SegReaderCursorFree(pToken->pSegcsr); + pToken->pSegcsr = 0; + }else{ + /* Set nLoad4 to the value of (4^nOther) for the next iteration of the + ** for-loop. Except, limit the value to 2^24 to prevent it from + ** overflowing the 32-bit integer it is stored in. */ + if( ii<12 ) nLoad4 = nLoad4*4; + + if( ii==0 || pTC->pPhrase->nToken>1 ){ + /* Either this is the cheapest token in the entire query, or it is + ** part of a multi-token phrase. Either way, the entire doclist will + ** (eventually) be loaded into memory. It may as well be now. */ Fts3PhraseToken *pToken = pTC->pToken; int nList = 0; char *pList = 0; - rc = fts3TermSelect(pTab, pToken, pTC->iCol, 1, &nList, &pList); + rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList); assert( rc==SQLITE_OK || pList==0 ); - if( rc==SQLITE_OK ){ - nDocEst = fts3DoclistCountDocids(1, pList, nList); + int nCount; fts3EvalPhraseMergeToken(pTab, pTC->pPhrase, pTC->iToken,pList,nList); + nCount = fts3DoclistCountDocids( + pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll + ); + if( ii==0 || nCountnOvfl>=(nDocEst*nDocSize) ){ - Fts3PhraseToken *pToken = pTC->pToken; - rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); - fts3SegReaderCursorFree(pToken->pSegcsr); - pToken->pSegcsr = 0; - } - nDocEst = 1 + (nDocEst/4); } pTC->pToken = 0; } @@ -3721,36 +4228,29 @@ static int fts3EvalSelectDeferred( return rc; } -int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){ +/* +** This function is called from within the xFilter method. It initializes +** the full-text query currently stored in pCsr->pExpr. To iterate through +** the results of a query, the caller does: +** +** fts3EvalStart(pCsr); +** while( 1 ){ +** fts3EvalNext(pCsr); +** if( pCsr->bEof ) break; +** ... return row pCsr->iPrevId to the caller ... +** } +*/ +static int fts3EvalStart(Fts3Cursor *pCsr){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc = SQLITE_OK; int nToken = 0; int nOr = 0; /* Allocate a MultiSegReader for each token in the expression. */ - fts3EvalAllocateReaders(pCsr, pExpr, &nToken, &nOr, &rc); + fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); - /* Call fts3EvalPhraseStart() on all phrases in the expression. TODO: - ** This call will eventually also be responsible for determining which - ** tokens are 'deferred' until the document text is loaded into memory. - ** - ** Each token in each phrase is dealt with using one of the following - ** three strategies: - ** - ** 1. Entire doclist loaded into memory as part of the - ** fts3EvalStartReaders() call. - ** - ** 2. Doclist loaded into memory incrementally, as part of each - ** sqlite3Fts3EvalNext() call. - ** - ** 3. Token doclist is never loaded. Instead, documents are loaded into - ** memory and scanned for the token as part of the sqlite3Fts3EvalNext() - ** call. This is known as a "deferred" token. - */ - - /* If bOptOk is true, check if there are any tokens that should be deferred. - */ - if( rc==SQLITE_OK && bOptOk && nToken>1 && pTab->bHasStat ){ + /* Determine which, if any, tokens in the expression should be deferred. */ + if( rc==SQLITE_OK && nToken>1 && pTab->bHasStat ){ Fts3TokenAndCost *aTC; Fts3Expr **apOr; aTC = (Fts3TokenAndCost *)sqlite3_malloc( @@ -3766,7 +4266,7 @@ int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){ Fts3TokenAndCost *pTC = aTC; Fts3Expr **ppOr = apOr; - fts3EvalTokenCosts(pCsr, 0, pExpr, &pTC, &ppOr, &rc); + fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc); nToken = pTC-aTC; nOr = ppOr-apOr; @@ -3781,11 +4281,14 @@ int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){ } } - fts3EvalStartReaders(pCsr, pExpr, bOptOk, &rc); + fts3EvalStartReaders(pCsr, pCsr->pExpr, 1, &rc); return rc; } -static void fts3EvalZeroPoslist(Fts3Phrase *pPhrase){ +/* +** Invalidate the current position list for phrase pPhrase. +*/ +static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){ if( pPhrase->doclist.bFreeList ){ sqlite3_free(pPhrase->doclist.pList); } @@ -3794,8 +4297,30 @@ static void fts3EvalZeroPoslist(Fts3Phrase *pPhrase){ pPhrase->doclist.bFreeList = 0; } -static int fts3EvalNearTrim2( - int nNear, +/* +** This function is called to edit the position list associated with +** the phrase object passed as the fifth argument according to a NEAR +** condition. For example: +** +** abc NEAR/5 "def ghi" +** +** Parameter nNear is passed the NEAR distance of the expression (5 in +** the example above). When this function is called, *paPoslist points to +** the position list, and *pnToken is the number of phrase tokens in, the +** phrase on the other side of the NEAR operator to pPhrase. For example, +** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to +** the position list associated with phrase "abc". +** +** All positions in the pPhrase position list that are not sufficiently +** close to a position in the *paPoslist position list are removed. If this +** leaves 0 positions, zero is returned. Otherwise, non-zero. +** +** Before returning, *paPoslist is set to point to the position lsit +** associated with pPhrase. And *pnToken is set to the number of tokens in +** pPhrase. +*/ +static int fts3EvalNearTrim( + int nNear, /* NEAR distance. As in "NEAR/nNear". */ char *aTmp, /* Temporary space to use */ char **paPoslist, /* IN/OUT: Position list */ int *pnToken, /* IN/OUT: Tokens in phrase of *paPoslist */ @@ -3827,6 +4352,172 @@ static int fts3EvalNearTrim2( return res; } +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is called. +** Otherwise, it advances the expression passed as the second argument to +** point to the next matching row in the database. Expressions iterate through +** matching rows in docid order. Ascending order if Fts3Cursor.bDesc is zero, +** or descending if it is non-zero. +** +** If an error occurs, *pRc is set to an SQLite error code. Otherwise, if +** successful, the following variables in pExpr are set: +** +** Fts3Expr.bEof (non-zero if EOF - there is no next row) +** Fts3Expr.iDocid (valid if bEof==0. The docid of the next row) +** +** If the expression is of type FTSQUERY_PHRASE, and the expression is not +** at EOF, then the following variables are populated with the position list +** for the phrase for the visited row: +** +** FTs3Expr.pPhrase->doclist.nList (length of pList in bytes) +** FTs3Expr.pPhrase->doclist.pList (pointer to position list) +** +** It says above that this function advances the expression to the next +** matching row. This is usually true, but there are the following exceptions: +** +** 1. Deferred tokens are not taken into account. If a phrase consists +** entirely of deferred tokens, it is assumed to match every row in +** the db. In this case the position-list is not populated at all. +** +** Or, if a phrase contains one or more deferred tokens and one or +** more non-deferred tokens, then the expression is advanced to the +** next possible match, considering only non-deferred tokens. In other +** words, if the phrase is "A B C", and "B" is deferred, the expression +** is advanced to the next row that contains an instance of "A * C", +** where "*" may match any single token. The position list in this case +** is populated as for "A * C" before returning. +** +** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is +** advanced to point to the next row that matches "x AND y". +** +** See fts3EvalTestDeferredAndNear() for details on testing if a row is +** really a match, taking into account deferred tokens and NEAR operators. +*/ +static void fts3EvalNextRow( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pExpr, /* Expr. to advance to next matching row */ + int *pRc /* IN/OUT: Error code */ +){ + if( *pRc==SQLITE_OK ){ + int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */ + assert( pExpr->bEof==0 ); + pExpr->bStart = 1; + + switch( pExpr->eType ){ + case FTSQUERY_NEAR: + case FTSQUERY_AND: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + assert( !pLeft->bDeferred || !pRight->bDeferred ); + + if( pLeft->bDeferred ){ + /* LHS is entirely deferred. So we assume it matches every row. + ** Advance the RHS iterator to find the next row visited. */ + fts3EvalNextRow(pCsr, pRight, pRc); + pExpr->iDocid = pRight->iDocid; + pExpr->bEof = pRight->bEof; + }else if( pRight->bDeferred ){ + /* RHS is entirely deferred. So we assume it matches every row. + ** Advance the LHS iterator to find the next row visited. */ + fts3EvalNextRow(pCsr, pLeft, pRc); + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = pLeft->bEof; + }else{ + /* Neither the RHS or LHS are deferred. */ + fts3EvalNextRow(pCsr, pLeft, pRc); + fts3EvalNextRow(pCsr, pRight, pRc); + while( !pLeft->bEof && !pRight->bEof && *pRc==SQLITE_OK ){ + sqlite3_int64 iDiff = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + if( iDiff==0 ) break; + if( iDiff<0 ){ + fts3EvalNextRow(pCsr, pLeft, pRc); + }else{ + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = (pLeft->bEof || pRight->bEof); + } + break; + } + + case FTSQUERY_OR: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + + assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); + assert( pRight->bStart || pLeft->iDocid==pRight->iDocid ); + + if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ + fts3EvalNextRow(pCsr, pLeft, pRc); + }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){ + fts3EvalNextRow(pCsr, pRight, pRc); + }else{ + fts3EvalNextRow(pCsr, pLeft, pRc); + fts3EvalNextRow(pCsr, pRight, pRc); + } + + pExpr->bEof = (pLeft->bEof && pRight->bEof); + iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ + pExpr->iDocid = pLeft->iDocid; + }else{ + pExpr->iDocid = pRight->iDocid; + } + + break; + } + + case FTSQUERY_NOT: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + + if( pRight->bStart==0 ){ + fts3EvalNextRow(pCsr, pRight, pRc); + assert( *pRc!=SQLITE_OK || pRight->bStart ); + } + + fts3EvalNextRow(pCsr, pLeft, pRc); + if( pLeft->bEof==0 ){ + while( !*pRc + && !pRight->bEof + && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0 + ){ + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = pLeft->bEof; + break; + } + + default: { + Fts3Phrase *pPhrase = pExpr->pPhrase; + fts3EvalInvalidatePoslist(pPhrase); + *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof); + pExpr->iDocid = pPhrase->doclist.iDocid; + break; + } + } + } +} + +/* +** If *pRc is not SQLITE_OK, or if pExpr is not the root node of a NEAR +** cluster, then this function returns 1 immediately. +** +** Otherwise, it checks if the current row really does match the NEAR +** expression, using the data currently stored in the position lists +** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression. +** +** If the current row is a match, the position list associated with each +** phrase in the NEAR expression is edited in place to contain only those +** phrase instances sufficiently close to their peers to satisfy all NEAR +** constraints. In this case it returns 1. If the NEAR expression does not +** match the current row, 0 is returned. The position lists may or may not +** be edited if 0 is returned. +*/ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ int res = 1; @@ -3848,7 +4539,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ ** ** The right-hand child of a NEAR node is always a phrase. The ** left-hand child may be either a phrase or a NEAR node. There are - ** no exceptions to this. + ** no exceptions to this - it's the way the parser in fts3_expr.c works. */ if( *pRc==SQLITE_OK && pExpr->eType==FTSQUERY_NEAR @@ -3875,17 +4566,20 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ Fts3Phrase *pPhrase = p->pRight->pPhrase; int nNear = p->nNear; - res = fts3EvalNearTrim2(nNear, aTmp, &aPoslist, &nToken, pPhrase); + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); } aPoslist = pExpr->pRight->pPhrase->doclist.pList; nToken = pExpr->pRight->pPhrase->nToken; for(p=pExpr->pLeft; p && res; p=p->pLeft){ - int nNear = p->pParent->nNear; - Fts3Phrase *pPhrase = ( + int nNear; + Fts3Phrase *pPhrase; + assert( p->pParent && p->pParent->pLeft==p ); + nNear = p->pParent->nNear; + pPhrase = ( p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase ); - res = fts3EvalNearTrim2(nNear, aTmp, &aPoslist, &nToken, pPhrase); + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); } } @@ -3896,128 +4590,29 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ } /* -** This macro is used by the fts3EvalNext() function. The two arguments are -** 64-bit docid values. If the current query is "ORDER BY docid ASC", then -** the macro returns (i1 - i2). Or if it is "ORDER BY docid DESC", then -** it returns (i2 - i1). This allows the same code to be used for merging -** doclists in ascending or descending order. +** This function is a helper function for fts3EvalTestDeferredAndNear(). +** Assuming no error occurs or has occurred, It returns non-zero if the +** expression passed as the second argument matches the row that pCsr +** currently points to, or zero if it does not. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** If an error occurs during execution of this function, *pRc is set to +** the appropriate SQLite error code. In this case the returned value is +** undefined. */ -#define DOCID_CMP(i1, i2) ((pCsr->bDesc?-1:1) * (i1-i2)) - -static void fts3EvalNext( - Fts3Cursor *pCsr, - Fts3Expr *pExpr, - int *pRc +static int fts3EvalTestExpr( + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Expr to test. May or may not be root. */ + int *pRc /* IN/OUT: Error code */ ){ - if( *pRc==SQLITE_OK ){ - assert( pExpr->bEof==0 ); - pExpr->bStart = 1; - - switch( pExpr->eType ){ - case FTSQUERY_NEAR: - case FTSQUERY_AND: { - Fts3Expr *pLeft = pExpr->pLeft; - Fts3Expr *pRight = pExpr->pRight; - assert( !pLeft->bDeferred || !pRight->bDeferred ); - if( pLeft->bDeferred ){ - fts3EvalNext(pCsr, pRight, pRc); - pExpr->iDocid = pRight->iDocid; - pExpr->bEof = pRight->bEof; - }else if( pRight->bDeferred ){ - fts3EvalNext(pCsr, pLeft, pRc); - pExpr->iDocid = pLeft->iDocid; - pExpr->bEof = pLeft->bEof; - }else{ - fts3EvalNext(pCsr, pLeft, pRc); - fts3EvalNext(pCsr, pRight, pRc); - - while( !pLeft->bEof && !pRight->bEof && *pRc==SQLITE_OK ){ - sqlite3_int64 iDiff = DOCID_CMP(pLeft->iDocid, pRight->iDocid); - if( iDiff==0 ) break; - if( iDiff<0 ){ - fts3EvalNext(pCsr, pLeft, pRc); - }else{ - fts3EvalNext(pCsr, pRight, pRc); - } - } - - pExpr->iDocid = pLeft->iDocid; - pExpr->bEof = (pLeft->bEof || pRight->bEof); - } - break; - } - - case FTSQUERY_OR: { - Fts3Expr *pLeft = pExpr->pLeft; - Fts3Expr *pRight = pExpr->pRight; - sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); - - assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); - assert( pRight->bStart || pLeft->iDocid==pRight->iDocid ); - - if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ - fts3EvalNext(pCsr, pLeft, pRc); - }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){ - fts3EvalNext(pCsr, pRight, pRc); - }else{ - fts3EvalNext(pCsr, pLeft, pRc); - fts3EvalNext(pCsr, pRight, pRc); - } - - pExpr->bEof = (pLeft->bEof && pRight->bEof); - iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); - if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ - pExpr->iDocid = pLeft->iDocid; - }else{ - pExpr->iDocid = pRight->iDocid; - } - - break; - } - - case FTSQUERY_NOT: { - Fts3Expr *pLeft = pExpr->pLeft; - Fts3Expr *pRight = pExpr->pRight; - - if( pRight->bStart==0 ){ - fts3EvalNext(pCsr, pRight, pRc); - assert( *pRc!=SQLITE_OK || pRight->bStart ); - } - - fts3EvalNext(pCsr, pLeft, pRc); - if( pLeft->bEof==0 ){ - while( !*pRc - && !pRight->bEof - && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0 - ){ - fts3EvalNext(pCsr, pRight, pRc); - } - } - pExpr->iDocid = pLeft->iDocid; - pExpr->bEof = pLeft->bEof; - break; - } - - default: { - Fts3Phrase *pPhrase = pExpr->pPhrase; - fts3EvalZeroPoslist(pPhrase); - *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof); - pExpr->iDocid = pPhrase->doclist.iDocid; - break; - } - } - } -} - -static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){ - int bHit = 1; + int bHit = 1; /* Return value */ if( *pRc==SQLITE_OK ){ switch( pExpr->eType ){ case FTSQUERY_NEAR: case FTSQUERY_AND: bHit = ( - fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc) - && fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc) + fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) + && fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) && fts3EvalNearTest(pExpr, pRc) ); @@ -4043,27 +4638,27 @@ static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){ Fts3Expr *p; for(p=pExpr; p->pPhrase==0; p=p->pLeft){ if( p->pRight->iDocid==pCsr->iPrevId ){ - fts3EvalZeroPoslist(p->pRight->pPhrase); + fts3EvalInvalidatePoslist(p->pRight->pPhrase); } } if( p->iDocid==pCsr->iPrevId ){ - fts3EvalZeroPoslist(p->pPhrase); + fts3EvalInvalidatePoslist(p->pPhrase); } } break; case FTSQUERY_OR: { - int bHit1 = fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc); - int bHit2 = fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc); + int bHit1 = fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc); + int bHit2 = fts3EvalTestExpr(pCsr, pExpr->pRight, pRc); bHit = bHit1 || bHit2; break; } case FTSQUERY_NOT: bHit = ( - fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc) - && !fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc) + fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) + && !fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) ); break; @@ -4074,7 +4669,7 @@ static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){ Fts3Phrase *pPhrase = pExpr->pPhrase; assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 ); if( pExpr->bDeferred ){ - fts3EvalZeroPoslist(pPhrase); + fts3EvalInvalidatePoslist(pPhrase); } *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); bHit = (pPhrase->doclist.pList!=0); @@ -4090,27 +4685,49 @@ static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){ } /* -** Return 1 if both of the following are true: +** This function is called as the second part of each xNext operation when +** iterating through the results of a full-text query. At this point the +** cursor points to a row that matches the query expression, with the +** following caveats: +** +** * Up until this point, "NEAR" operators in the expression have been +** treated as "AND". +** +** * Deferred tokens have not yet been considered. +** +** If *pRc is not SQLITE_OK when this function is called, it immediately +** returns 0. Otherwise, it tests whether or not after considering NEAR +** operators and deferred tokens the current row is still a match for the +** expression. It returns 1 if both of the following are true: ** ** 1. *pRc is SQLITE_OK when this function returns, and ** ** 2. After scanning the current FTS table row for the deferred tokens, -** it is determined that the row does not match the query. +** it is determined that the row does *not* match the query. ** ** Or, if no error occurs and it seems the current row does match the FTS ** query, return 0. */ -static int fts3EvalLoadDeferred(Fts3Cursor *pCsr, int *pRc){ +static int fts3EvalTestDeferredAndNear(Fts3Cursor *pCsr, int *pRc){ int rc = *pRc; int bMiss = 0; if( rc==SQLITE_OK ){ + + /* If there are one or more deferred tokens, load the current row into + ** memory and scan it to determine the position list for each deferred + ** token. Then, see if this row is really a match, considering deferred + ** tokens and NEAR operators (neither of which were taken into account + ** earlier, by fts3EvalNextRow()). + */ if( pCsr->pDeferred ){ rc = fts3CursorSeek(0, pCsr); if( rc==SQLITE_OK ){ rc = sqlite3Fts3CacheDeferredDoclists(pCsr); } } - bMiss = (0==fts3EvalDeferredTest(pCsr, pCsr->pExpr, &rc)); + bMiss = (0==fts3EvalTestExpr(pCsr, pCsr->pExpr, &rc)); + + /* Free the position-lists accumulated for each deferred token above. */ sqlite3Fts3FreeDeferredDoclists(pCsr); *pRc = rc; } @@ -4121,7 +4738,7 @@ static int fts3EvalLoadDeferred(Fts3Cursor *pCsr, int *pRc){ ** Advance to the next document that matches the FTS expression in ** Fts3Cursor.pExpr. */ -int sqlite3Fts3EvalNext(Fts3Cursor *pCsr){ +static int fts3EvalNext(Fts3Cursor *pCsr){ int rc = SQLITE_OK; /* Return Code */ Fts3Expr *pExpr = pCsr->pExpr; assert( pCsr->isEof==0 ); @@ -4133,19 +4750,19 @@ int sqlite3Fts3EvalNext(Fts3Cursor *pCsr){ sqlite3_reset(pCsr->pStmt); } assert( sqlite3_data_count(pCsr->pStmt)==0 ); - fts3EvalNext(pCsr, pExpr, &rc); + fts3EvalNextRow(pCsr, pExpr, &rc); pCsr->isEof = pExpr->bEof; pCsr->isRequireSeek = 1; pCsr->isMatchinfoNeeded = 1; pCsr->iPrevId = pExpr->iDocid; - }while( pCsr->isEof==0 && fts3EvalLoadDeferred(pCsr, &rc) ); + }while( pCsr->isEof==0 && fts3EvalTestDeferredAndNear(pCsr, &rc) ); } return rc; } /* ** Restart interation for expression pExpr so that the next call to -** sqlite3Fts3EvalNext() visits the first row. Do not allow incremental +** fts3EvalNext() visits the first row. Do not allow incremental ** loading or merging of phrase doclists for this iteration. ** ** If *pRc is other than SQLITE_OK when this function is called, it is @@ -4161,7 +4778,7 @@ static void fts3EvalRestart( Fts3Phrase *pPhrase = pExpr->pPhrase; if( pPhrase ){ - fts3EvalZeroPoslist(pPhrase); + fts3EvalInvalidatePoslist(pPhrase); if( pPhrase->bIncr ){ assert( pPhrase->nToken==1 ); assert( pPhrase->aToken[0].pSegcsr ); @@ -4277,14 +4894,14 @@ static int fts3EvalGatherStats( assert( sqlite3_data_count(pCsr->pStmt)==0 ); /* Advance to the next document */ - fts3EvalNext(pCsr, pRoot, &rc); + fts3EvalNextRow(pCsr, pRoot, &rc); pCsr->isEof = pRoot->bEof; pCsr->isRequireSeek = 1; pCsr->isMatchinfoNeeded = 1; pCsr->iPrevId = pRoot->iDocid; }while( pCsr->isEof==0 && pRoot->eType==FTSQUERY_NEAR - && fts3EvalLoadDeferred(pCsr, &rc) + && fts3EvalTestDeferredAndNear(pCsr, &rc) ); if( rc==SQLITE_OK && pCsr->isEof==0 ){ @@ -4306,10 +4923,10 @@ static int fts3EvalGatherStats( */ fts3EvalRestart(pCsr, pRoot, &rc); do { - fts3EvalNext(pCsr, pRoot, &rc); + fts3EvalNextRow(pCsr, pRoot, &rc); assert( pRoot->bEof==0 ); }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); - fts3EvalLoadDeferred(pCsr, &rc); + fts3EvalTestDeferredAndNear(pCsr, &rc); } } return rc; @@ -4440,7 +5057,7 @@ void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){ if( pPhrase ){ int i; sqlite3_free(pPhrase->doclist.aAll); - fts3EvalZeroPoslist(pPhrase); + fts3EvalInvalidatePoslist(pPhrase); memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist)); for(i=0; inToken; i++){ fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr); @@ -4449,4 +5066,27 @@ void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){ } } +/* +** Return SQLITE_CORRUPT_VTAB. +*/ +#ifdef SQLITE_DEBUG +int sqlite3Fts3Corrupt(){ + return SQLITE_CORRUPT_VTAB; +} +#endif + +#if !SQLITE_CORE +/* +** Initialize API pointer table, if required. +*/ +int sqlite3_extension_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + return sqlite3Fts3Init(db); +} +#endif + #endif diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index 16643796..78392ec3 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -27,7 +27,14 @@ # define SQLITE_ENABLE_FTS3 #endif -#ifdef SQLITE_ENABLE_FTS3 +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* If not building as part of the core, include sqlite3ext.h. */ +#ifndef SQLITE_CORE +# include "sqlite3ext.h" +extern const sqlite3_api_routines *sqlite3_api; +#endif + #include "sqlite3.h" #include "fts3_tokenizer.h" #include "fts3_hash.h" @@ -150,6 +157,13 @@ typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */ #endif /* SQLITE_AMALGAMATION */ +#ifdef SQLITE_DEBUG +int sqlite3Fts3Corrupt(void); +# define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() +#else +# define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB +#endif + typedef struct Fts3Table Fts3Table; typedef struct Fts3Cursor Fts3Cursor; typedef struct Fts3Expr Fts3Expr; @@ -177,6 +191,7 @@ struct Fts3Table { int nColumn; /* number of named columns in virtual table */ char **azColumn; /* column names. malloced */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ + char *zContentTbl; /* content=xxx option, or NULL */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. @@ -217,7 +232,7 @@ struct Fts3Table { int nPendingData; /* Current bytes of pending data */ sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ -#if defined(SQLITE_DEBUG) +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) /* State variables used for validating that the transaction control ** methods of the virtual table are called at appropriate times. These ** values do not contribution to the FTS computation; they are used for @@ -290,7 +305,7 @@ struct Fts3Doclist { int bFreeList; /* True if pList should be sqlite3_free()d */ char *pList; /* Pointer to position list following iDocid */ int nList; /* Length of position list */ -} doclist; +}; /* ** A "phrase" is a sequence of one or more tokens that must match in @@ -302,6 +317,7 @@ struct Fts3PhraseToken { char *z; /* Text of the token */ int n; /* Number of bytes in buffer z */ int isPrefix; /* True if token ends with a "*" character */ + int bFirst; /* True if token must appear at position 0 */ /* Variables above this point are populated when the expression is ** parsed (by code in fts3_expr.c). Below this point the variables are @@ -420,6 +436,7 @@ int sqlite3Fts3SegReaderCursor( #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 #define FTS3_SEGMENT_PREFIX 0x00000008 #define FTS3_SEGMENT_SCAN 0x00000010 +#define FTS3_SEGMENT_FIRST 0x00000020 /* Type passed as 4th argument to SegmentReaderIterate() */ struct Fts3SegFilter { @@ -459,8 +476,8 @@ int sqlite3Fts3GetVarint32(const char *, int *); int sqlite3Fts3VarintLen(sqlite3_uint64); void sqlite3Fts3Dequote(char *); void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); - int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); +int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); /* fts3_tokenizer.c */ const char *sqlite3Fts3NextToken(const char *, int *); @@ -479,7 +496,7 @@ void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); /* fts3_expr.c */ int sqlite3Fts3ExprParse(sqlite3_tokenizer *, - char **, int, int, const char *, int, Fts3Expr ** + char **, int, int, int, const char *, int, Fts3Expr ** ); void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST @@ -490,19 +507,8 @@ int sqlite3Fts3InitTerm(sqlite3 *db); /* fts3_aux.c */ int sqlite3Fts3InitAux(sqlite3 *db); -int sqlite3Fts3TermSegReaderCursor( - Fts3Cursor *pCsr, /* Virtual table cursor handle */ - const char *zTerm, /* Term to query for */ - int nTerm, /* Size of zTerm in bytes */ - int isPrefix, /* True for a prefix search */ - Fts3MultiSegReader **ppSegcsr /* OUT: Allocated seg-reader cursor */ -); - void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); -int sqlite3Fts3EvalStart(Fts3Cursor *, Fts3Expr *, int); -int sqlite3Fts3EvalNext(Fts3Cursor *pCsr); - int sqlite3Fts3MsrIncrStart( Fts3Table*, Fts3MultiSegReader*, int, const char*, int); int sqlite3Fts3MsrIncrNext( @@ -513,5 +519,5 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *); -#endif /* SQLITE_ENABLE_FTS3 */ +#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c index 7eb2962d..1c3a7907 100644 --- a/ext/fts3/fts3_expr.c +++ b/ext/fts3/fts3_expr.c @@ -93,6 +93,7 @@ typedef struct ParseContext ParseContext; struct ParseContext { sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ const char **azCol; /* Array of column names for fts3 table */ + int bFts4; /* True to allow FTS4-only syntax */ int nCol; /* Number of entries in azCol[] */ int iDefaultCol; /* Default column to query */ int isNot; /* True if getNextNode() sees a unary - */ @@ -180,9 +181,21 @@ static int getNextToken( pRet->pPhrase->aToken[0].isPrefix = 1; iEnd++; } - if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){ - pParse->isNot = 1; + + while( 1 ){ + if( !sqlite3_fts3_enable_parentheses + && iStart>0 && z[iStart-1]=='-' + ){ + pParse->isNot = 1; + iStart--; + }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){ + pRet->pPhrase->aToken[0].bFirst = 1; + iStart--; + }else{ + break; + } } + } nConsumed = iEnd; } @@ -281,6 +294,7 @@ static int getNextString( pToken->n = nByte; pToken->isPrefix = (iEndbFirst = (iBegin>0 && zInput[iBegin-1]=='^'); nToken = ii+1; } } @@ -302,8 +316,12 @@ static int getNextString( p->pPhrase->nToken = nToken; zBuf = (char *)&p->pPhrase->aToken[nToken]; - memcpy(zBuf, zTemp, nTemp); - sqlite3_free(zTemp); + if( zTemp ){ + memcpy(zBuf, zTemp, nTemp); + sqlite3_free(zTemp); + }else{ + assert( nTemp==0 ); + } for(jj=0; jjpPhrase->nToken; jj++){ p->pPhrase->aToken[jj].z = zBuf; @@ -728,6 +746,7 @@ exprparse_out: int sqlite3Fts3ExprParse( sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ char **azCol, /* Array of column names for fts3 table */ + int bFts4, /* True to allow FTS4-only syntax */ int nCol, /* Number of entries in azCol[] */ int iDefaultCol, /* Default column to query */ const char *z, int n, /* Text of MATCH query */ @@ -741,6 +760,7 @@ int sqlite3Fts3ExprParse( sParse.nCol = nCol; sParse.iDefaultCol = iDefaultCol; sParse.nNest = 0; + sParse.bFts4 = bFts4; if( z==0 ){ *ppExpr = 0; return SQLITE_OK; @@ -930,7 +950,7 @@ static void fts3ExprTest( } rc = sqlite3Fts3ExprParse( - pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr + pTokenizer, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr ); if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ sqlite3_result_error(context, "Error parsing expression", -1); diff --git a/ext/fts3/fts3_hash.c b/ext/fts3/fts3_hash.c index b7c3e8b5..57c59b58 100644 --- a/ext/fts3/fts3_hash.c +++ b/ext/fts3/fts3_hash.c @@ -30,7 +30,6 @@ #include #include -#include "sqlite3.h" #include "fts3_hash.h" /* diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index b569eb13..23ef25c5 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -368,6 +368,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ int iFirst = 0; pPhrase->pList = pCsr; fts3GetDeltaPosition(&pCsr, &iFirst); + assert( iFirst>=0 ); pPhrase->pHead = pCsr; pPhrase->pTail = pCsr; pPhrase->iHead = iFirst; @@ -848,7 +849,7 @@ static int fts3MatchinfoSelectDoctotal( a = sqlite3_column_blob(pStmt, 0); a += sqlite3Fts3GetVarint(a, &nDoc); - if( nDoc==0 ) return SQLITE_CORRUPT_VTAB; + if( nDoc==0 ) return FTS_CORRUPT_VTAB; *pnDoc = (u32)nDoc; if( paLen ) *paLen = a; @@ -1409,7 +1410,7 @@ void sqlite3Fts3Offsets( if( !pTerm ){ /* All offsets for this column have been gathered. */ - break; + rc = SQLITE_DONE; }else{ assert( iCurrent<=iMinPos ); if( 0==(0xFE&*pTerm->pList) ){ @@ -1426,8 +1427,8 @@ void sqlite3Fts3Offsets( "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart ); rc = fts3StringAppend(&res, aBuffer, -1); - }else if( rc==SQLITE_DONE ){ - rc = SQLITE_CORRUPT_VTAB; + }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){ + rc = FTS_CORRUPT_VTAB; } } } diff --git a/ext/fts3/fts3_test.c b/ext/fts3/fts3_test.c index c5f72d84..72735f3d 100644 --- a/ext/fts3/fts3_test.c +++ b/ext/fts3/fts3_test.c @@ -19,6 +19,8 @@ #include #include +#ifdef SQLITE_TEST + /* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */ #include "fts3Int.h" @@ -319,3 +321,4 @@ int Sqlitetestfts3_Init(Tcl_Interp *interp){ ); return TCL_OK; } +#endif /* ifdef SQLITE_TEST */ diff --git a/ext/fts3/fts3_tokenizer.c b/ext/fts3/fts3_tokenizer.c index c4ad6a5c..6494bb96 100644 --- a/ext/fts3/fts3_tokenizer.c +++ b/ext/fts3/fts3_tokenizer.c @@ -23,12 +23,7 @@ ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ -#include "sqlite3ext.h" -#ifndef SQLITE_CORE - SQLITE_EXTENSION_INIT1 -#endif #include "fts3Int.h" - #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #include diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 36f2249e..2904a9ac 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -256,7 +256,7 @@ static int fts3SqlStmt( /* 4 */ "DELETE FROM %Q.'%q_segdir'", /* 5 */ "DELETE FROM %Q.'%q_docsize'", /* 6 */ "DELETE FROM %Q.'%q_stat'", -/* 7 */ "SELECT %s FROM %Q.'%q_content' AS x WHERE rowid=?", +/* 7 */ "SELECT %s WHERE rowid=?", /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", /* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", /* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", @@ -298,7 +298,7 @@ static int fts3SqlStmt( if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ - zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist, p->zDb, p->zName); + zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); } @@ -341,7 +341,7 @@ static int fts3SelectDocsize( rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){ rc = sqlite3_reset(pStmt); - if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT_VTAB; + if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB; pStmt = 0; }else{ rc = SQLITE_OK; @@ -409,17 +409,24 @@ static void fts3SqlExec( ** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can ** still happen if the user reads data directly from the %_segments or ** %_segdir tables instead of going through FTS3 though. +** +** This reasoning does not apply to a content=xxx table. */ int sqlite3Fts3ReadLock(Fts3Table *p){ int rc; /* Return code */ sqlite3_stmt *pStmt; /* Statement used to obtain lock */ - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_null(pStmt, 1); - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); + if( p->zContentTbl==0 ){ + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_null(pStmt, 1); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } + }else{ + rc = SQLITE_OK; } + return rc; } @@ -780,6 +787,18 @@ static int fts3InsertData( int rc; /* Return code */ sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ + if( p->zContentTbl ){ + sqlite3_value *pRowid = apVal[p->nColumn+3]; + if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ + pRowid = apVal[1]; + } + if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ + return SQLITE_CONSTRAINT; + } + *piDocid = sqlite3_value_int64(pRowid); + return SQLITE_OK; + } + /* Locate the statement handle used to insert data into the %_content ** table. The SQL for this statement is: ** @@ -830,14 +849,16 @@ static int fts3InsertData( ** Remove all data from the FTS3 table. Clear the hash table containing ** pending terms. */ -static int fts3DeleteAll(Fts3Table *p){ +static int fts3DeleteAll(Fts3Table *p, int bContent){ int rc = SQLITE_OK; /* Return code */ /* Discard the contents of the pending-terms hash table. */ sqlite3Fts3PendingTermsClear(p); - /* Delete everything from the %_content, %_segments and %_segdir tables. */ - fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); + /* Delete everything from the shadow tables. Except, leave %_content as + ** is if bContent is false. */ + assert( p->zContentTbl==0 || bContent==0 ); + if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); if( p->bHasDocsize ){ @@ -1145,7 +1166,7 @@ static int fts3SegReaderNext( if( nPrefix<0 || nSuffix<=0 || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] ){ - return SQLITE_CORRUPT_VTAB; + return FTS_CORRUPT_VTAB; } if( nPrefix+nSuffix>pReader->nTermAlloc ){ @@ -1175,7 +1196,7 @@ static int fts3SegReaderNext( if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) ){ - return SQLITE_CORRUPT_VTAB; + return FTS_CORRUPT_VTAB; } return SQLITE_OK; } @@ -2125,12 +2146,18 @@ static void fts3SegWriterFree(SegmentWriter *pWriter){ static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ sqlite3_stmt *pStmt; int rc; - rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); - if( rc==SQLITE_OK ){ - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - *pisEmpty = sqlite3_column_int(pStmt, 0); + if( p->zContentTbl ){ + /* If using the content=xxx option, assume the table is never empty */ + *pisEmpty = 0; + rc = SQLITE_OK; + }else{ + rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pisEmpty = sqlite3_column_int(pStmt, 0); + } + rc = sqlite3_reset(pStmt); } - rc = sqlite3_reset(pStmt); } return rc; } @@ -2482,6 +2509,7 @@ int sqlite3Fts3SegReaderStep( int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); + int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST); Fts3SegReader **apSegment = pCsr->apSegment; int nSegment = pCsr->nSegment; @@ -2541,6 +2569,7 @@ int sqlite3Fts3SegReaderStep( assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); if( nMerge==1 && !isIgnoreEmpty + && !isFirst && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) ){ pCsr->nDoclist = apSegment[0]->nDoclist; @@ -2606,12 +2635,24 @@ int sqlite3Fts3SegReaderStep( } pCsr->aBuffer = aNew; } - nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); - iPrev = iDocid; - if( isRequirePos ){ - memcpy(&pCsr->aBuffer[nDoclist], pList, nList); - nDoclist += nList; - pCsr->aBuffer[nDoclist++] = '\0'; + + if( isFirst ){ + char *a = &pCsr->aBuffer[nDoclist]; + int nWrite; + + nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); + if( nWrite ){ + iPrev = iDocid; + nDoclist += nWrite; + } + }else{ + nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); + iPrev = iDocid; + if( isRequirePos ){ + memcpy(&pCsr->aBuffer[nDoclist], pList, nList); + nDoclist += nList; + pCsr->aBuffer[nDoclist++] = '\0'; + } } } @@ -2787,9 +2828,9 @@ static void fts3DecodeIntArray( ** a blob of varints. */ static void fts3InsertDocsize( - int *pRC, /* Result code */ - Fts3Table *p, /* Table into which to insert */ - u32 *aSz /* Sizes of each column */ + int *pRC, /* Result code */ + Fts3Table *p, /* Table into which to insert */ + u32 *aSz /* Sizes of each column, in tokens */ ){ char *pBlob; /* The BLOB encoding of the document size */ int nBlob; /* Number of bytes in the BLOB */ @@ -2911,6 +2952,86 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; } +/* +** This function is called when the user executes the following statement: +** +** INSERT INTO () VALUES('rebuild'); +** +** The entire FTS index is discarded and rebuilt. If the table is one +** created using the content=xxx option, then the new index is based on +** the current contents of the xxx table. Otherwise, it is rebuilt based +** on the contents of the %_content table. +*/ +static int fts3DoRebuild(Fts3Table *p){ + int rc; /* Return Code */ + + rc = fts3DeleteAll(p, 0); + if( rc==SQLITE_OK ){ + u32 *aSz = 0; + u32 *aSzIns = 0; + u32 *aSzDel = 0; + sqlite3_stmt *pStmt = 0; + int nEntry = 0; + + /* Compose and prepare an SQL statement to loop through the content table */ + char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } + + if( rc==SQLITE_OK ){ + int nByte = sizeof(u32) * (p->nColumn+1)*3; + aSz = (u32 *)sqlite3_malloc(nByte); + if( aSz==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(aSz, 0, nByte); + aSzIns = &aSz[p->nColumn+1]; + aSzDel = &aSzIns[p->nColumn+1]; + } + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + int iCol; + rc = fts3PendingTermsDocid(p, sqlite3_column_int64(pStmt, 0)); + aSz[p->nColumn] = 0; + for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ + const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); + rc = fts3PendingTermsAdd(p, z, iCol, &aSz[iCol]); + aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); + } + if( p->bHasDocsize ){ + fts3InsertDocsize(&rc, p, aSz); + } + if( rc!=SQLITE_OK ){ + sqlite3_finalize(pStmt); + pStmt = 0; + }else{ + nEntry++; + for(iCol=0; iCol<=p->nColumn; iCol++){ + aSzIns[iCol] += aSz[iCol]; + } + } + } + if( p->bHasStat ){ + fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry); + } + sqlite3_free(aSz); + + if( pStmt ){ + int rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + + return rc; +} + /* ** Handle a 'special' INSERT of the form: ** @@ -2928,6 +3049,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ return SQLITE_NOMEM; }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ rc = fts3DoOptimize(p, 0); + }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ + rc = fts3DoRebuild(p); #ifdef SQLITE_TEST }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ p->nNodeSize = atoi(&zVal[9]); @@ -3008,6 +3131,7 @@ int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){ for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ Fts3PhraseToken *pPT = pDef->pToken; if( (pDef->iCol>=p->nColumn || pDef->iCol==i) + && (pPT->bFirst==0 || iPos==0) && (pPT->n==nToken || (pPT->isPrefix && pPT->nz, pPT->n)) ){ @@ -3099,14 +3223,18 @@ static int fts3DeleteByRowid( /* Deleting this row means the whole table is empty. In this case ** delete the contents of all three tables and throw away any ** data in the pendingTerms hash table. */ - rc = fts3DeleteAll(p); + rc = fts3DeleteAll(p, 1); *pnDoc = *pnDoc - 1; }else{ sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); rc = fts3PendingTermsDocid(p, iRemove); fts3DeleteTerms(&rc, p, pRowid, aSzDel); - fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); - if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; + if( p->zContentTbl==0 ){ + fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); + if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; + }else{ + *pnDoc = *pnDoc - 1; + } if( p->bHasDocsize ){ fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); } @@ -3129,7 +3257,6 @@ int sqlite3Fts3UpdateMethod( Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return Code */ int isRemove = 0; /* True for an UPDATE or DELETE */ - sqlite3_int64 iRemove = 0; /* Rowid removed by UPDATE or DELETE */ u32 *aSzIns = 0; /* Sizes of inserted documents */ u32 *aSzDel; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ @@ -3167,7 +3294,7 @@ int sqlite3Fts3UpdateMethod( ** detect the conflict and return SQLITE_CONSTRAINT before beginning to ** modify the database file. */ - if( nArg>1 ){ + if( nArg>1 && p->zContentTbl==0 ){ /* Find the value object that holds the new rowid value. */ sqlite3_value *pNewRowid = apVal[3+p->nColumn]; if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ @@ -3212,19 +3339,21 @@ int sqlite3Fts3UpdateMethod( assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); isRemove = 1; - iRemove = sqlite3_value_int64(apVal[0]); } /* If this is an INSERT or UPDATE operation, insert the new record. */ if( nArg>1 && rc==SQLITE_OK ){ if( bInsertDone==0 ){ rc = fts3InsertData(p, apVal, pRowid); - if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT_VTAB; + if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ + rc = FTS_CORRUPT_VTAB; + } } - if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){ + if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ rc = fts3PendingTermsDocid(p, *pRowid); } if( rc==SQLITE_OK ){ + assert( p->iPrevDocid==*pRowid ); rc = fts3InsertTerms(p, apVal, aSzIns); } if( p->bHasDocsize ){ diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 2375069e..884482ea 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -1268,7 +1268,8 @@ static int rtreeFilter( rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); - assert( (idxStr==0 && argc==0) || (int)strlen(idxStr)==argc*2 ); + assert( (idxStr==0 && argc==0) + || (idxStr && (int)strlen(idxStr)==argc*2) ); for(ii=0; iiaConstraint[ii]; p->op = idxStr[ii*2]; @@ -1569,7 +1570,10 @@ static int ChooseLeaf( float fMinGrowth = 0.0; float fMinArea = 0.0; +#if VARIANT_RSTARTREE_CHOOSESUBTREE float fMinOverlap = 0.0; + float overlap; +#endif int nCell = NCELL(pNode); RtreeCell cell; @@ -1601,7 +1605,6 @@ static int ChooseLeaf( int bBest = 0; float growth; float area; - float overlap = 0.0; nodeGetCell(pRtree, pNode, iCell, &cell); growth = cellGrowth(pRtree, &cell, pCell); area = cellArea(pRtree, &cell); @@ -1609,6 +1612,8 @@ static int ChooseLeaf( #if VARIANT_RSTARTREE_CHOOSESUBTREE if( ii==(pRtree->iDepth-1) ){ overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell); + }else{ + overlap = 0.0; } if( (iCell==0) || (overlap>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c +sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl + tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros + echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c + cat sqlite3.c >>tclsqlite3.c + echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c + echo '#line 1 "tclsqlite.c"' >>tclsqlite3.c + cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c + +sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl + tclsh $(TOP)/tool/split-sqlite3c.tcl + fts2amal.c: target_source $(TOP)/ext/fts2/mkfts2amal.tcl tclsh $(TOP)/ext/fts2/mkfts2amal.tcl @@ -417,7 +432,7 @@ tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR) # 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 + $(NAWK) -f $(TOP)/mkopcodec.awk opcodes.h >opcodes.c opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk cat parse.h $(TOP)/src/vdbe.c | \ @@ -506,6 +521,16 @@ tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a $(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \ $(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB) +sqlite3_analyzer.c: sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl + echo "#define TCLSH 2" > $@ + cat sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c >> $@ + echo "static const char *tclsh_main_loop(void){" >> $@ + echo "static const char *zMainloop = " >> $@ + $(NAWK) -f $(TOP)/tool/tostr.awk $(TOP)/tool/spaceanal.tcl >> $@ + echo "; return zMainloop; }" >> $@ + +sqlite3_analyzer$(EXE): sqlite3_analyzer.c + $(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB) # Rules to build the 'testfixture' application. # @@ -548,16 +573,6 @@ threadtest3$(EXE): sqlite3.o $(TOP)/test/threadtest3.c $(TOP)/test/tt3_checkpoin threadtest: threadtest3$(EXE) ./threadtest3$(EXE) -sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c sqlite3.c $(TESTSRC) \ - $(TOP)/tool/spaceanal.tcl - $(NAWK) -f $(TOP)/tool/tostr.awk $(TOP)/tool/spaceanal.tcl \ - >spaceanal_tcl.h - $(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) - TEST_EXTENSION = $(SHPREFIX)testloadext.$(SO) $(TEST_EXTENSION): $(TOP)/src/test_loadext.c $(MKSHLIB) $(TOP)/src/test_loadext.c -o $(TEST_EXTENSION) @@ -565,6 +580,13 @@ $(TEST_EXTENSION): $(TOP)/src/test_loadext.c extensiontest: testfixture$(EXE) $(TEST_EXTENSION) ./testfixture$(EXE) $(TOP)/test/loadext.test +# This target will fail if the SQLite amalgamation contains any exported +# symbols that do not begin with "sqlite3_". It is run as part of the +# releasetest.tcl script. +# +checksymbols: sqlite3.o + nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0 + # Standard install and cleanup targets # @@ -574,10 +596,16 @@ install: sqlite3 libsqlite3.a sqlite3.h mv sqlite3.h /usr/include clean: - rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.* - rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h + rm -f *.o sqlite3 sqlite3.exe libsqlite3.a sqlite3.h opcodes.* + rm -f lemon lemon.exe lempar.c parse.* sqlite*.tar.gz + rm -f mkkeywordhash mkkeywordhash.exe keywordhash.h rm -f $(PUBLISH) rm -f *.da *.bb *.bbg gmon.out rm -rf tsrc target_source rm -f testloadext.dll libtestloadext.so + rm -f amalgamation-testfixture amalgamation-testfixture.exe + rm -f fts3-testfixture fts3-testfixture.exe + rm -f testfixture testfixture.exe + rm -f threadtest3 threadtest3.exe rm -f sqlite3.c fts?amal.c tclsqlite3.c + rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c diff --git a/manifest b/manifest index b2251f24..307b0c39 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Release\scandidate\s3.7.7.1. -D 2011-06-28T17:39:05.200 +C Version\s3.7.9 +D 2011-11-01T00:52:41.132 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in c1d7a7f4fd8da6b1815032efca950e3d5125407e +F Makefile.in a162fe39e249b8ed4a65ee947c30152786cfe897 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 11082f65b452b908d93013292c17850378c39284 -F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151 +F Makefile.msc dcad80fa69f17d46fe6778ba873fc108ca16298d +F Makefile.vxworks 1deb39c8bb047296c30161ffa10c1b5423e632f9 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 -F VERSION 5d587aa6adf86fd587768fe736359bd9f5e43890 +F VERSION bb37c274b503bbe73f00ea4f374eb817cba4b171 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531 F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248 @@ -23,10 +23,10 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 405a958bdb3af382a809dccb08a44694923ddd61 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure b8e6049719c5f649670388236e2253183243b873 x +F configure 806c06aef5895860da49600ce098dbe4d5a8435c x F configure.ac 298a759c086e72c013da459c2aec02a104f4224f F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad -F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 +F doc/lemon.html 3091574143dd3415669b6745843ff8d011d33549 F doc/pager-invariants.txt 870107036470d7c419e93768676fae2f8749cf9e F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1 @@ -59,32 +59,33 @@ F ext/fts2/fts2_tokenizer.c 26e993a00b2bd5b6e73c155597361710b12ffe25 F ext/fts2/fts2_tokenizer.h a7e46462d935a314b2682287f12f27530a3ee08e F ext/fts2/fts2_tokenizer1.c 0123d21078e053bd98fd6186c5c6dc6d67969f2e F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 +F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c ca776037493d0081da70a6afc0df80f5ce347cb7 +F ext/fts3/fts3.c 246ef2d0cef67517d156d39c9247cd6c432f0d79 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h fa493ccbad78a2c99ad1c984f651c0c202e68536 +F ext/fts3/fts3Int.h def7a900f98c5ab5fa4772e922bfa219d5097f05 F ext/fts3/fts3_aux.c 0ebfa7b86cf8ff6a0861605fcc63b83ec1b70691 -F ext/fts3/fts3_expr.c 23791de01b3a5d313d76e02befd2601d4096bc2b -F ext/fts3/fts3_hash.c aad95afa01cf2a5ffaa448e4b0ab043880cd1efb +F ext/fts3/fts3_expr.c f5df26bddf46a5916b2a5f80c4027996e92b7b15 +F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec F ext/fts3/fts3_icu.c 6c8f395cdf9e1e3afa7fadb7e523dbbf381c6dfa F ext/fts3/fts3_porter.c 8d946908f4812c005d3d33fcbe78418b1f4eb70c -F ext/fts3/fts3_snippet.c 58b2ba2b934c1e2a2f6ac857d7f3c7e1a14b4532 +F ext/fts3/fts3_snippet.c 1f9ee6a8e0e242649645968dcec4deb253d86c2a F ext/fts3/fts3_term.c a5457992723455a58804cb75c8cbd8978db5c2ef -F ext/fts3/fts3_test.c c0aae3219df989d3e827d07846097adf8cb09945 -F ext/fts3/fts3_tokenizer.c 6089986ebcfc19d4b7aabd2b92773368efa4354f +F ext/fts3/fts3_test.c 24fa13f330db011500acb95590da9eee24951894 +F ext/fts3/fts3_tokenizer.c 9ff7ec66ae3c5c0340fa081958e64f395c71a106 F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 0dde8f307b8045565cf63797ba9acfaff1c50c68 -F ext/fts3/fts3_write.c 194829c8fd024a448fc899e5ff02a8ed06595529 +F ext/fts3/fts3_write.c c097228bff4d33c6b8a270c9717b9f8339068776 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c b431c54d1ed05f04f2987e8a4fbb931acb40c312 +F ext/rtree/rtree.c 692e9192d148f318b3dca9f744600346a175eedd F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba @@ -104,11 +105,11 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 -F main.mk d799fb600383cee11fed58876a7cccb749dd2614 +F main.mk ac48970ca7506c9034f5c7b2212111fbeb0a1aaa F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac -F mkopcodec.awk 3fb9bf077053c968451f4dd03d11661ac373f9d1 +F mkopcodec.awk f6fccee29e68493bfd90a2e0466ede5fa94dd2fc F mkopcodeh.awk 29b84656502eee5f444c3147f331ee686956ab0e F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F publish.sh 313c5b2425f2cf5e547db7549a9796acc4508f22 @@ -118,90 +119,90 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5 -F src/analyze.c a425d62e8fa9ebcb4359ab84ff0c62c6563d2e2a +F src/analyze.c 5a1db16a651ce6310c8b046b2cbb736e030e14b9 F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 -F src/backup.c 986c15232757f2873dff35ee3b35cbf935fc573c +F src/backup.c 4368158da74d4711888e03264105c5c527d76caf F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 8c46f0ab69ad9549c75a3a91fed87abdaa743e2f +F src/btree.c 32199e2d939233ade25340eaba450f818b37c079 F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3 -F src/build.c 5a428625d21ad409514afb40ad083bee25dd957a +F src/build.c 8af67a08a852ff4c63701963cb1ab7166f577814 F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac -F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4 -F src/date.c d3c11de76392ea62637bfac0f4655889fc2f5a85 -F src/delete.c 4925f9121525fc871f5d8d13c1f7dcc91abb38bb -F src/expr.c ab46ab0f0c44979a8164ca31728d7d10ae5e8106 +F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33 +F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 +F src/delete.c ff68e5ef23aee08c0ff528f699a19397ed8bbed8 +F src/expr.c fbf116f90cabc917ae50bba24a73a0b55519a0c8 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c 9fabba17a4d4778dc660f0cb9d781fc86d7b9d41 -F src/func.c 59bb046d7e3df1ab512ac339ccb0a6f996a17cb7 -F src/global.c c70a46f28680f8d7c097dbc0430ccf3b932e90b0 +F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5 +F src/func.c 6261ce00aad9c63cd5b4219249b05683979060e9 +F src/global.c e230227de13601714b29f9363028514aada5ae2f F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 3eea5a53d2644116fb865afaa4699fabe62b441c +F src/insert.c ca18783512323f74aaf4ee74b46ffd75ec80d031 F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f -F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e -F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85 -F src/main.c fa654e1802e14a5f6c09c37971c3b69c1001d9c8 +F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416 +F src/loadext.c d0d2022a5a07274d408820b978b9e549189d314f +F src/main.c df06f5229b8046f85dde253dfd7fe35ae9e4902e F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf -F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3 +F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f F src/memjournal.c 0ebce851677a7ac035ba1512a7e65851b34530c6 F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f -F src/mutex.h fe2ef5e1c4dae531d5a544f9241f19c56d26803d +F src/mutex.h 2a79e0c10c26412546b501ee0f3d92b42decf63e F src/mutex_noop.c d5cfbca87168c661a0b118cd8e329a908e453151 F src/mutex_os2.c 882d735098c07c8c6a5472b8dd66e19675fe117f F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579 F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 -F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d +F src/os.c 5d9b02782ed36345348d6fe21d7762ed3a9cfd2a F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 -F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f +F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 -F src/os_unix.c 07acbb3e074e52b48a4248c06f66c9a91db1a0ce -F src/os_win.c eafcd6b91cf204a7ef29ac1ef2a1b7132e132e58 -F src/pager.c 120550e7ef01dafaa2cbb4a0528c0d87c8f12b41 -F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 +F src/os_unix.c ddda0b1c5ae536669634d7bff31b3f8f4d654866 +F src/os_win.c 49d418916428a59d773f39993db0ecde56ab4c37 +F src/pager.c ad62daa0c21e27ae332b3ceb4f579a2a97046ddc +F src/pager.h 9f81b08efb06db4ba8be69446e10b005c351373d F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/pcache.c 49e718c095810c6b3334e3a6d89970aceaddefce F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 -F src/pcache1.c 912bd5687d6df344698d8e69560f347b6e21c18a -F src/pragma.c ebcd20f1e654f5cb3aeef864ed69c4697719fbaa +F src/pcache1.c 24f5e85a78514584b46190260ba7ab0a66312197 +F src/pragma.c da8ef96b3eec351e81e0061c39810e548bcc96d7 F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4 -F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1 +F src/printf.c 03104cbff6959ff45df69dc9060ba6212f60a869 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 -F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 +F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 -F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff -F src/shell.c 0e0173b3e79d956368013e759f084caa7995ecb1 -F src/sqlite.h.in 4b7255c10d39c5faf089dbd29cde7c367ff39f1f -F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h 7b72f7c6929757c0678d94524dbc7e7e3d6dc398 +F src/select.c 80f3ac44a8514b1d107b80f5df4a424ae059d2b6 +F src/shell.c f0ab793261ab045a0b8c47fa2707e8a894d2898f +F src/sqlite.h.in ff950aef7b378963c67add42dda5d446a0b7330e +F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 +F src/sqliteInt.h c74457cd2c4bd77683bac76e698bf2ec2d3e13f9 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d -F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf +F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c 5db825be61708b1a2b3f8f6e185e9b753829acef -F src/test1.c 8eef932f1024f1076a8adb8a6f5d9c5267c9e969 +F src/tclsqlite.c de581e2e71f5e7f98366156afad83b4742ac6fe0 +F src/test1.c 0f41b7c67719207a5de24b009e172c4dcf189827 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 F src/test5.c e1a19845625144caf038031234a12185e40d315c -F src/test6.c c7256cc21d2409486d094277d5b017e8eced44ba +F src/test6.c 3191b4ab964a144230ff9ef96c093520375c7b2a F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843 -F src/test8.c 6b1d12912a04fe6fca8c45bb9c3ea022f4352228 +F src/test8.c 99f70341d6ec480313775127f4cd14b4a47db557 F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 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 791a9acbf9a695cf9c12ff6bbe874dfde9a8c5f3 +F src/test_config.c bc8826296a7b3a86eeaba1ac2af5551d1c20c35b F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5 @@ -212,83 +213,84 @@ F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99 F src/test_intarray.h 489edb9068bb926583445cb02589344961054207 F src/test_journal.c 03313c693cca72959dcaaf79f8d76f21c01e19ff F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e -F src/test_malloc.c 7ca7be34e0e09ef0ed6619544552ed95732e41f6 -F src/test_multiplex.c a7457a1ac46964b7f897d75ecfd447410ec067e6 +F src/test_malloc.c 8d416f29ad8573f32601f6056c9d2b17472e9ad5 +F src/test_multiplex.c 3fc368022c46fe44ec22c5e1ed727223a54a6a1d F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8 -F src/test_quota.c cc4f67e12558a252ea4a11720be268348f4b1595 -F src/test_rtree.c 30c981837445a4e187ee850a49c4760d9642f7c3 +F src/test_quota.c a391c866217e92986c6f523f05b08aa6956c8419 +F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f -F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c +F src/test_stat.c 69de4361c7a69fc1136d31ab7144408cd00805c7 F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd -F src/test_syscall.c 162c4ec0137a549c009bb9ecab550527743cfc5d +F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa -F src/test_thread.c fe9a7803fc1d69cccb60f016f28c1cedf2d9fcfa -F src/test_vfs.c 956cb3f5cbd2a0d09129540e615bb0fb761c083d +F src/test_thread.c 35022393dd54d147b998b6b7f7e945b01114d666 +F src/test_vfs.c b0baec983bd6f872715a4b44c8f39104fec333af F src/test_vfstrace.c 0b884e06094a746da729119a2cabdc7aa790063d F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705 -F src/trigger.c c836a6caac16ba96611558922106858f6ca3d6bf -F src/update.c 80d77311d91ebc06b27149e75701f1b3e9356622 -F src/utf.c c53eb7404b3eb5c1cbb5655c6a7a0e0ce6bd50f0 -F src/util.c 0f33bbbdfcc4a2d8cf20c3b2a16ffc3b57c58a70 -F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e -F src/vdbe.c 50b5b4ef29d928a4f60905f820ee1ab2f8ced29f -F src/vdbe.h 5cf09e7ee8a3f7d93bc51f196a96550786afe7a1 -F src/vdbeInt.h ad84226cc0adcb1185c22b70696b235a1678bb45 -F src/vdbeapi.c 2f908c65337b16c6249ab378d477e74492cf759b -F src/vdbeaux.c 4d100407e3c72e163854aff8903d19d5ecdf46c0 -F src/vdbeblob.c f024f0bf420f36b070143c32b15cc7287341ffd3 -F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b +F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56 +F src/update.c 25e046a8f69d5e557aabde2000487b8545509d8d +F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84 +F src/util.c df83983bd57057df4951516880066b42b7055269 +F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa +F src/vdbe.c 326994a64a9a08853122200dc9f62cb96b8f0831 +F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755 +F src/vdbeInt.h 9498fc98a2c9e349a4ef13455ff5a3e898f40176 +F src/vdbeapi.c 4dbba7f94f127f6ea8d2d0505ee1f98e5ffbf546 +F src/vdbeaux.c a950e34449a508d48d90475acc287943a4094f3a +F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb +F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56 +F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790 F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 -F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582 -F src/wal.c 0c70ad7b1cac6005fa5e2cbefd23ee05e391c290 +F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a +F src/wal.c 9658df8d404b82e6b2d40fd05944463214e2d935 F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5 -F test/8_3_names.test b93687beebd17f6ebf812405a6833bae5d1f4199 +F src/where.c 7c85f4c93058e27100d404f0777aaeb0d1b296ae +F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 -F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125 -F test/alter.test a3f570072b53d7c0fe463bab3f5affa8e113c487 -F test/alter2.test 75f731508f1bf27ba09a6075c66cd02216ba464b -F test/alter3.test 8677e48d95536f7a6ed86a1a774744dadcc22b07 -F test/alter4.test 1e5dd6b951e9f65ca66422edff02e56df82dd403 +F test/all.test 52fc8dee494092031a556911d404ca30a749a30b +F test/alter.test 66f5818f9848c4f22de022a345fae25bcd30f8fb +F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 +F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d +F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5 F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc -F test/analyze.test c8cb89e8736336f1f0646c8123e6028a14c7b55e -F test/analyze2.test 8f2b1534d43f5547ce9a6b736c021d4192c75be3 -F test/analyze3.test d61f55d8b472fc6e713160b1e577f7a68e63f38b +F test/analyze.test f8ab7d15858b4093b06caf5e57e2a5ff7104bdae +F test/analyze3.test c3c7f6c3951900c188cf94b2d5ee3246d6b3ff89 F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045 -F test/analyze5.test 1de8d66b11aae5a1453aa042d62e834a476bac9c -F test/analyze6.test c125622a813325bba1b4999040ddc213773c2290 -F test/analyze7.test 5508e7828164ea0b518ed219bed7320a481863d4 -F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3 -F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6 -F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e +F test/analyze5.test 713354664c5ff1853ab2cbcb740f0cf5cb7c802e +F test/analyze6.test bd3625806a5ee6f7bef72d06295bd319f0290af2 +F test/analyze7.test d3587aa5af75c9048d031b94fceca2534fa75d1d +F test/analyze8.test 4ca170de2ba30ccb1af2c0406803db72262f9691 +F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b +F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b +F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a -F test/async5.test f3592d79c84d6e83a5f50d3fd500445f7d97dfdf -F test/attach.test 2bb09073d7d5499127db00f50780766dcea913e1 -F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437 -F test/attach3.test bd9830bc3a0d22ed1310c9bff6896927937017dc -F test/attach4.test 31f9eb0ca7bdbc393cc4657b877903a226a83d4b -F test/attachmalloc.test 1d5b821a676f7bf0b00d87cc106b78966789ba57 -F test/auth.test b047105c32da7db70b842fd24056723125ecc2ff +F test/async5.test 0dd8701bd588bf6e70c2557a22ae3f22b2567b4c +F test/attach.test 0e6f8de2589f11a5f474ef57fe5af2877e61c0e8 +F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966 +F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e +F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c +F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0 +F test/auth.test 304e82f31592820d3bde26ab6b75deaa123e1a6f F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882 F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 -F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46 -F test/autoindex1.test 860fc83f4fefb0c68ad062afc3ff43faa1534fc4 -F test/autovacuum.test bb7c0885e6f8f1d633045de48f2b66082162766d -F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6 +F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf +F test/autoindex1.test 058d0b331ae6840a61bbee910d8cbae27bfd5991 +F test/autovacuum.test fcaf4616ae5bb18098db1cb36262565e5c841c3c +F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 -F test/backcompat.test 0f23ff8d516acdf42f3d866a66d85306de2d02bc -F test/backup.test 004d3b78bffd990741ab50133ed4347c25c172b1 -F test/backup2.test b7c69f937c912e85ac8a5dbd1e1cf290302b2d49 -F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38 +F test/backcompat.test 71eeb75ea567c060774c4e8db4b0e703f21c7677 +F test/backup.test 6970614b002b056ae5bab5b76559905e02b6f0b2 +F test/backup2.test b4966934b2dc10a9a6546114566ea69b34a5185e +F test/backup_ioerr.test 40d208bc9224b666ee3ed423f49bc9062a36a9d0 F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f @@ -310,9 +312,9 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/cache.test 754baab2f18089fc9bcba7afaeb4dc907c6c6de2 F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360 -F test/capi3.test 5c1ea6c940f2d7c4d5af8ef1ec2f92a267d2e37a +F test/capi3.test 7200dff6acb17b9a4b6f9918f554eaae04968ddd F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 -F test/capi3c.test bea67403a5e37a4b33230ee4723e315a2ffb31e7 +F test/capi3c.test ccf0acf045dbacd09f6229aa4efed670aaba76a9 F test/capi3d.test cd36571f014f34bdc4421967f6453cbb597d5d16 F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 @@ -322,88 +324,92 @@ F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04 F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49 F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c F test/collate4.test 3d3f123f83fd8ccda6f48d617e44e661b9870c7d -F test/collate5.test fe0f43c4740d7b71b959cac668d19e42f2e06e4d +F test/collate5.test 67f1d3e848e230ff4802815a79acb0a8b5e69bd7 F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907 -F test/collate7.test fac8db7aac3978466c04ae892cc74dcf2bc031aa +F test/collate7.test 8ec29d98f3ee4ccebce6e16ce3863fb6b8c7b868 F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6 F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6 F test/colmeta.test 087c42997754b8c648819832241daf724f813322 F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b F test/conflict.test cabc41f7616675df71b4fddabca3bd5d9221915a -F test/corrupt.test 1a5bef8b2d178859af69814ecedcd37219a89968 -F test/corrupt2.test 808a28d0ca3b97e9aa8c91cd2b485ea2700b76d1 -F test/corrupt3.test e3006aaf579d2ed7f1b94bf4cc695d3c784fa5af +F test/corrupt.test 4aabd06cff3fe759e3e658bcc17b71789710665e +F test/corrupt2.test 9c0ab4becd50e9050bc1ebb8675456a4e5587bf0 +F test/corrupt3.test 889d7cdb811800303aa722d7813fe8a4299cf726 F test/corrupt4.test b963f9e01e0f92d15c76fb0747876fd4b96dc30a F test/corrupt5.test c23da7bfb20917cc7fdbb13ee25c7cc4e9fffeff F test/corrupt6.test 4e4161aef1f30b9f34582bb4142334b7f47eacae F test/corrupt7.test a90caf89c7d7cb7893ea4d92529bd0c129317ee4 F test/corrupt8.test 48eb37ffb9a03bceada62219e2bd4c92f4b0cb75 -F test/corrupt9.test fad0bc26a5c972580a8d763c62f24094f4e8ef25 -F test/corruptA.test 856ea7a2eb5c1c767abbdf02679ac6cb158e4643 -F test/corruptB.test 44133515cf46c4d7bba691e3bcfa478080413af0 -F test/corruptC.test 483aa35dadfd96bdf549e38d75ffc2942576477e -F test/corruptD.test 63a449a3146b460231535d04a409d14ce71795ad -F test/corruptE.test 7290b61145d954be549340e462ca84826d8a31a3 +F test/corrupt9.test 959179e68dc0b7b99f424cf3e0381c86dcdd0112 +F test/corruptA.test fafa652aa585753be4f6b62ff0bb250266eaf7ce +F test/corruptB.test 20d4a20cbed23958888c3e8995b424a47223d647 +F test/corruptC.test 62a767fe64acb1975f58cc6171192839c783edbb +F test/corruptD.test 99b1999dbfa7cc04aaeac9d695a2445d4e7c7458 +F test/corruptE.test 1b9eb20a8711251ce57b44a257e241085b39b52d F test/count.test 454e1ce985c94d13efeac405ce54439f49336163 -F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89 +F test/crash.test 519dc29f6fea151f015a23236e555239353946eb F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651 -F test/crash3.test 776f9363554c029fcce71d9e6600fa0ba6359ce7 -F test/crash4.test 02ff4f15c149ca1e88a5c299b4896c84d9450c3b -F test/crash5.test 80a2f7073381837fc082435c97df52a830abcd80 -F test/crash6.test 9c730cf06335003cb1f5cfceddacd044155336e0 -F test/crash7.test e20a7b9ee1d16eaef7c94a4cb7ed2191b4d05970 -F test/crash8.test 76b95451933fe172ce8e26bff22d5c663c8ae473 +F test/crash3.test 8f5de9d32ab9ab95475a9efe7f47a940aa889418 +F test/crash4.test fe2821baf37168dc59dd733dcf7dba2a401487bc +F test/crash5.test 69226a1b948d8961395b7ad2a1df084c212ce8cf +F test/crash6.test 4c56f1e40d0291e1110790a99807aa875b1647ba +F test/crash7.test 6c6a369af266af2ef50ab34df8f94d719065e2c1 +F test/crash8.test 38767cb504bbe491de6be4a7006b154973a2309f F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 -F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272 +F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8 F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47 F test/date.test a18a2ce81add84b17b06559e82ad7bb91bc6ddff -F test/dbstatus.test 175b088308f2ce3f7afb8208f25c10878ee05921 +F test/dbstatus.test 9eb484ba837c6f3f9bbcaecc29e6060a8c3ba6d2 +F test/dbstatus2.test dc57b0d9610851c0ff58a8e1b5b191678398b72a F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc -F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4 +F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701 F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab -F test/descidx1.test b1353c1a15cfbee97b13a1dcedaf0fe78163ba6a +F test/descidx1.test 533dcbda614b0463b0ea029527fd27e5a9ab2d66 F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f -F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb +F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e +F test/distinct.test df5b11ad606439129c88720a86787bc9ca181f31 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 F test/e_createtable.test 4771686a586b6ae414f927c389b2c101cc05c028 F test/e_delete.test e2ae0d3fce5efd70fef99025e932afffc5616fab F test/e_droptrigger.test ddd4b28ed8a3d81bd5153fa0ab7559529a2ca03a F test/e_dropview.test b347bab30fc8de67b131594b3cd6f3d3bdaa753d -F test/e_expr.test 71b55f90c9336ecec5a99641679036931260c754 +F test/e_expr.test d93ccded2409c66637dc1649a02f169e041b63d8 F test/e_fkey.test 38039b840ab19331000b0f0eb1d82baa7208a67a -F test/e_fts3.test 75bb0aee26384ef586165e21018a17f7cd843469 +F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 F test/e_insert.test 76d4bb5da9b28014d515d91ffe29a79a1e99f2bc F test/e_reindex.test a064f0878b8f848fbca38f1f61f82f15a3000c64 F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 -F test/e_select.test 7ac53674e822d4d77bbb4a9a4aaefa5fdc9e493f +F test/e_select.test 8d7fac7a268eaeb80b9a7ba7964505b9d30f5458 F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92 F test/e_update.test b926341a65955d69a6375c9eb4fd82e7089bc83a F test/e_uri.test 6f35b491f80dac005c8144f38b2dfb4d96483596 F test/e_vacuum.test 6c09c2af7f2f140518f371c5342100118f779dcf F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea -F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398 -F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041 -F test/enc4.test b145fa25feb56ea1d51a5bc43ca268c0cf691a67 +F test/enc2.test 796c59832e2b9a52842f382ffda8f3e989db03ad +F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 +F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020 F test/eqp.test f14fadd76da53405e9885e2431cacf7191d83cdb +F test/errmsg.test 3bb606db9d040cc6854459f8f5e5a2bcd9b7fd2a F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 -F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062 -F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b +F test/exclusive.test a1b324cb21834a490cd052d409d34789cfef57cb +F test/exclusive2.test 372be98f6de44dd78734e364b7b626ea211761a6 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 -F test/exists.test 5e2d64b4eb5a9d08876599bdae2e1213d2d12e2a +F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d -F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6 -F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e -F test/filefmt.test f178cfc29501a14565954c961b226e61877dd32c +F test/fallocate.test b5d34437bd7ab01d41b1464b8117aefd4d32160e +F test/filectrl.test 4eb0178956ca25a756e6d79711a90fec7157b454 +F test/filefmt.test ffa17b5aebc3eb4b1e3be1ccb5ee906ffbd97f6e F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da F test/fkey2.test 080969fe219b3b082b0e097ac18c6af2e5b0631f F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e F test/fkey4.test c6c8f9f9be885f95c85c7bceb26f243ad906fd49 -F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8 +F test/fkey_malloc.test c3a12acd053c976de09036498eef09b83afa4a80 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb +F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7 F test/fts1b.test 5d8a01aefbecc8b7442b36c94c05eb7a845462d5 F test/fts1c.test 85a525ce7428907469b4cce13d5563ce542ce64c @@ -411,12 +417,12 @@ F test/fts1d.test a73deace5c18df4a549b12908bade4f05dcf1a2f F test/fts1e.test 77244843e925560b5a0b70069c3e7ab62f181ed2 F test/fts1f.test 2d6cb10d8b7a4e6edc321bbdb3982f1f48774714 F test/fts1i.test 6bfe08cdfdced063a39a50c8601da65e6274d879 -F test/fts1j.test e4c0ffcd0ba2adce09c6b7b43ffd0749b5fda5c7 +F test/fts1j.test e3797475796043a161e348c46a309664cac83f7f F test/fts1k.test 65d3b41487b9f738d11b0f00eca375c0ca6bd970 F test/fts1l.test 15c119ed2362b2b28d5300c0540a6a43eab66c36 F test/fts1m.test 2d9ca67b095d49f037a914087cc0a61e89da4f0c F test/fts1n.test a2317dcd27b1d087ee3878b30e0a59c593c98b7a -F test/fts1o.test 382b8b07a2d6de5610814d9477117c4430464b9c +F test/fts1o.test fd92f82ea9090dbc2a13d4cd58aafe5afa371b6a F test/fts1porter.test d86e9c3e0c7f8ff95add6582b4b585fb4e02b96d F test/fts2.test e3fb95f96a650411574efc136f3fb10eef479ed7 F test/fts2a.test 473a5c8b473a4e21a8e3fddaed1e59666e0c6ab7 @@ -428,12 +434,12 @@ F test/fts2f.test cf84096235991709c1e61caa389632aa0a4f976d F test/fts2g.test d49d6f6c900e6e20a0fb980ec1cd568dee12af76 F test/fts2h.test 223af921323b409d4b5b18ff4e51619541b174bb F test/fts2i.test 1b22451d1f13f7c509baec620dc3a4a754885dd6 -F test/fts2j.test f68d7611f76309bc8b94170f3740d9fbbc061d9b +F test/fts2j.test 298fa1670aa21cd445b282d139b70c72e7ade12b F test/fts2k.test c7ebf4a4937594aa07459e3e1bca1251c1be8659 F test/fts2l.test 3333336621524cf7d60bb62d6ef6ab69647866ed F test/fts2m.test 4b30142ead6f3ed076e880a2a464064c5ad58c51 F test/fts2n.test 12b9c5352128cebd1c6b8395e43788d4b09087c2 -F test/fts2o.test c6a79567d85403dc4d15b89f3f9799a0a0aef065 +F test/fts2o.test 09cd920d585ebf1c2910b6be869efa286e308a84 F test/fts2p.test 4b48c35c91e6a7dbf5ac8d1e5691823cc999aafb F test/fts2q.test b2fbbe038b7a31a52a6079b215e71226d8c6a682 F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e @@ -449,14 +455,14 @@ F test/fts3af.test d394978c534eabf22dd0837e718b913fd66b499c F test/fts3ag.test 0b7d303f61ae5d620c4efb5e825713ea34ff9441 F test/fts3ah.test dc9f66c32c296f1bc8bcc4535126bddfeca62894 F test/fts3ai.test d29cee6ed653e30de478066881cec8aa766531b2 -F test/fts3aj.test 584facbc9ac4381a7ec624bfde677340ffc2a5a4 +F test/fts3aj.test 0ed71e1dd9b03b843a857dc3eb9b15630e0104fc F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8 F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 -F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9 +F test/fts3ao.test e7b80272efcced57d1d087a9da5c690dd7c21fd9 F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3 -F test/fts3auto.test f1cb0a55130897013ca5850dbee2945c2908a45a +F test/fts3auto.test c1a30b37002b7c764a96937fbc71065b73d69494 F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 @@ -465,65 +471,70 @@ F test/fts3conf.test 8e65ea56f88ced6cdd2252bdddb1a8327ae5af7e F test/fts3corrupt.test 7b0f91780ca36118d73324ec803187208ad33b32 F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 -F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52 -F test/fts3defer.test 7c8a38d5f617d7b52ae1c43ed73c536e7e895a35 +F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a +F test/fts3defer.test 2ea3fa028f8d9523f9c33dd8acc4555d567ea4ac F test/fts3defer2.test 35867d33ba6db03f6c73bd6f5fc333ae14f68c81 +F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297 F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851 F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a -F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246 -F test/fts3fault2.test dc96203af6ba31ce20163fc35460e1556e8edf4d -F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b -F test/fts3matchinfo.test 08a82d18cc08abb28aec41d412b4c2ef25ba6a5f +F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660 +F test/fts3fault2.test b62a2bc843c20414405f80e5eeb78e39bc68fe53 +F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 +F test/fts3malloc.test b86ea33db9e8c58c0c2f8027a9fcadaf6a1568be +F test/fts3matchinfo.test 6507fe1c342e542300d65ea637d4110eccf894e6 F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844 -F test/fts3prefix.test 36246609111ec1683f7ea5ed27666ce2cefb5676 +F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1 F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2 F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0 F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2 -F test/fts3snippet.test a12f22a3ba4dd59751a57c79b031d07ab5f51ddd -F test/fts3sort.test 63d52c1812904b751f9e1ff487472e44833f5402 -F test/fts4aa.test 148d9eb54901af23b5d402b1f388f43e559e1728 +F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2 +F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659 +F test/fts4aa.test 6e7f90420b837b2c685f3bcbe84c868492d40a68 +F test/fts4content.test 2624253c7e5a32d0c0d51f776dcd4526f0a51097 F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f -F test/func3.test 7ba2ca5a1e9bca900ba2c230cf04bd67184bc1bc +F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a 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 dd7001ac86d09c154a7dff064f4739c60e2b312c -F test/fuzzer1.test 3105b5a89a6cb0d475f0877debec942fe4143462 -F test/hook.test f2277c309e4ee8067d95d6b9b315568e9d5329b2 +F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 +F test/fuzzer1.test ddfb04f3bd5cfdda3b1aa15b78d3ad055c9cc50f +F test/hook.test 5f3749de6462a6b87b4209b74adf7df5ac2df639 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617 -F test/incrblob.test 76e787ca3301d9bfa6906031c626d26f8dd707de +F test/incrblob.test 3307c04876fe025e10256e3cc8050ab5a84aa27f F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19 F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7 -F test/incrblob_err.test c577c91d4ed9e8336cdb188b15d6ee2a6fe9604e +F test/incrblob_err.test d2562d2771ebffd4b3af89ef64c140dd44371597 F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0 -F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462 -F test/incrvacuum2.test ae04573b73ad52179f56e194fff0fbe43b509d23 -F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291 +F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32 +F test/incrvacuum2.test 62fbeb85459fe4e501684d8fb5b6e98a23e3b0c0 +F test/incrvacuum_ioerr.test 22f208d01c528403240e05beecc41dc98ed01637 F test/index.test b5429732b3b983fa810e3ac867d7ca85dae35097 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7 +F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026 F test/indexedby.test be501e381b82b2f8ab406309ba7aac46e221f4ad +F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 -F test/insert4.test b3e02648a5fc3075c29e13c369b5127bf859b5a2 -F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766 +F test/insert4.test 63ea672b0fc6d3a9a0ccee774a771510b1e684c4 +F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1 F test/intpkey.test 537669fd535f62632ca64828e435b9e54e8d677f -F test/io.test 1b895d6774491895cbc75659969f07ca01860c88 -F test/ioerr.test 622aebd2f24779cafaf5dd3e3c2b349ce40ade3b +F test/io.test b278aa8fa609ed0dcc825df31b2d9f526c5a52bd +F test/ioerr.test 40bb2cfcab63fb6aa7424cd97812a84bc16b5fb8 F test/ioerr2.test 1b56cb80d5b0726ee3ba325ca175734541e32955 F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd -F test/ioerr4.test fc6eddfec2efc2f1ed217b9eae4c1c1d3516ce86 +F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/join.test 8d63cc4d230a7affafa4b6ab0b97c49b8ccb365c F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324 @@ -531,40 +542,40 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901 -F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 -F test/journal2.test 50a3604768494d4a337f194f0a9480e7c57dcb72 -F test/journal3.test ff175219be1b02d2f7e54297ad7e491b7533edb6 -F test/jrnlmode.test e3fe6c4a2c3213d285650dc8e33aab7eaaa5ce53 -F test/jrnlmode2.test a19e28de1a6ec898067e46a122f1b71c9323bf00 -F test/jrnlmode3.test c6522b276ba315fd1416198de6fc1da9e72409fb +F test/journal1.test 8b71ef1ed5798bdc0e6eb616d8694e2c2c188d4d +F test/journal2.test 29937bdbb253bbfd92057610120bdc0aa7e84a0a +F test/journal3.test 6fd28532c88b447db844186bc190523108b6dbb4 +F test/jrnlmode.test 9ee3a78f53d52cca737db69293d15dc41c0cbd36 +F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d +F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test a47f52692aac96ba82508efba74819214cdebc17 +F test/like.test 7b4aaa4a8192fdec90e0a905984c92a688c51e48 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e -F test/loadext.test 0393ce12d9616aa87597dd0ec88181de181f6db0 +F test/loadext.test dab17f7014f8079698dbd4b02705562b0ce6db5f F test/loadext2.test 0bcaeb4d81cd5b6e883fdfea3c1bdbe1f173cbca F test/lock.test db74fdf5a73bad29ab3d862ea78bf1068972cc1d F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00 -F test/lock4.test c82268c031d39345d05efa672f80b025481b3ae5 -F test/lock5.test b2abb5e711bc59b0eae00f6c97a36ec9f458fada +F test/lock4.test e175ae13865bc87680607563bafba21f31a26f12 +F test/lock5.test 5ad6a1f536036ff1be915cfdd41481aeafda3273 F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5 F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64 F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95 F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2 -F test/main.test 9d7bbfcc1b52c88ba7b2ba6554068ecf9939f252 +F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8 F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9 -F test/malloc.test 76017be66cec4375a4b4ea5c71245e27a9fe2d0b -F test/malloc3.test 4128b1e6ffa506103b278ad97af89174f310c7ca +F test/malloc.test bc745155ff4252d4f35ec8316625b0dfe2abc659 +F test/malloc3.test de8eca0c3e748878845fdca3663ec4b642073caf F test/malloc4.test 957337613002b7058a85116493a262f679f3a261 -F test/malloc5.test 4d16d1bb26d2deddd7c4f480deec341f9b2d0e22 +F test/malloc5.test 30dc30b57fa22552eba0d8c95210d96c3d958a39 F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151 F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e -F test/mallocA.test 4b650c745aab289079454f4d1c02abe5c97ab6b3 +F test/mallocA.test 47006c8d70f29b030652e251cb9d35ba60289198 F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6 F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4 @@ -576,75 +587,75 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6 F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9 -F test/malloc_common.tcl 50d0ed21eed0ae9548b58935bd29ac89a05a54fa -F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c +F test/malloc_common.tcl 2930895b0962823ec679853e67e58dd6d8198b3c +F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 -F test/memsubsys1.test 679db68394a5692791737b150852173b3e2fea10 -F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc +F test/memsubsys1.test 16ce163ac1ace3d71bf0eaa6a821ed153addd91f +F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9 F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0 F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 -F test/misc1.test e56baf44656dd68d6475a4b44521045a60241e9b -F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd -F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6 +F test/misc1.test 55cb2bfbf4a8cd61f4be1effc30426ad41696bff +F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d +F test/misc3.test fe55130a43e444ee75e2156ff75dc96e964b5738 F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 -F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd +F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 -F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3 -F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33 -F test/multiplex.test 555080c87abfc72ba68e2f3df01d4a9a7a4fdf58 +F test/misc7.test eafaa41b9133d7a2ded4641bbe5f340731d35a52 +F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054 +F test/multiplex.test 9df8bf738b3b97c718fceb3fadb30900ba494418 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 -F test/nan.test dc212a22b36109fd1ae37154292444ef249c5ec2 -F test/notify1.test 8433bc74bd952fb8a6e3f8d7a4c2b28dfd69e310 -F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db -F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a +F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a +F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf +F test/notify2.test 9503e51b9a272a5405c205ad61b7623d5a9ca489 +F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 -F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/oserror.test 3fe52e0bd2891a9bf7cdeb639554992453d46301 -F test/pager1.test 228a831060dab96bc91b03ba2a85cedefd1ab38a +F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 +F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 +F test/pager1.test 1b630b3248c7d28862fe9e190cfe52234b502504 F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f -F test/pagerfault.test 4194b8ea2a5da7958cd155556605ff554e1b065a +F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442 F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401 F test/pagerfault3.test f16e2efcb5fc9996d1356f7cbc44c998318ae1d7 -F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 -F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb +F test/pageropt.test 9191867ed19a2b3db6c42d1b36b6fbc657cd1ab0 +F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 -F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16 -F test/permutations.test 1e8892ebf1bd6e9e8036f4841c72a91bf72da74a -F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850 -F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 -F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea +F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 +F test/permutations.test 522823b47238cb1754198f80817fe9f9158ede55 +F test/pragma.test 1ea0c85be853135bb7468e6eed48ee12b04794d4 +F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 +F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 -F test/quota.test 48c3a5a98687d67ef06fc16d2e603284756bbec3 +F test/quota.test 1c59a396e8f7b5d8466fa74b59f2aeb778d74f7a F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a -F test/releasetest.tcl c0c0865f1dff08dde08a964ef49e83217ebedbf8 -F test/rollback.test 1a83118ea6db4e7d8c10eaa63871b5e90502ffdc +F test/releasetest.tcl fa302d03fd9acfce6d910553a33473bfcf561958 +F test/rollback.test a1b4784b864331eae8b2a98c189efa2a8b11ff07 F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 -F test/savepoint.test a1bef7ace82cc7922975fa96b06176e9bd5114cf +F test/savepoint.test e575217b07d6a6e895e66f4eda076570815e0027 F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7 F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd -F test/savepoint6.test 76d3948568b2cdc0c13a671cadcae75009b183d6 +F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 F test/schema4.test e6a66e20cc69f0e306667c08be7fda3d11707dc5 -F test/securedel.test 328d2921c0ca49bdd3352e516b0377fc07143254 +F test/securedel.test 87a2561151af1f1e349071a89fdd77059f50113c F test/select1.test f67ca2dfc05df41c7b86eb32ca409b427a5f43b0 F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56 F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054 @@ -655,15 +666,15 @@ F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343 F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532 -F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b +F test/selectB.test 0d072c5846071b569766e6cd7f923f646a8b2bfa F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25 -F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c -F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e -F test/shared2.test 7f6ad2d857d0f4e5d6a0b9a897b5e56a6b6ea18c -F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962 -F test/shared4.test d0fadacb50bb6981b2fb9dc6d1da30fa1edddf83 -F test/shared6.test 990d2584b5db28e6e1f24742c711b26e59757b67 -F test/shared7.test 8114027cb5e8c376e467115703d46e5ac4e77739 +F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 +F test/shared.test 34945a516532b11182c3eb26e31247eee3c9ae48 +F test/shared2.test 8f71d4eb4d5261280de92284df74172545c852cc +F test/shared3.test ebf77f023f4bdaa8f74f65822b559e86ce5c6257 +F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d +F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9 +F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 @@ -675,32 +686,33 @@ F test/speed1.test f2974a91d79f58507ada01864c0e323093065452 F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb F test/speed1p.test c4a469f29f135f4d76c55b1f2a52f36e209466cc F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded -F test/speed3.test 5a419039e9da95d906adb2298af2849600c81c11 +F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b -F test/sqllimits1.test e90a0ed94452076f6a10209d378e06b5f75ef0a0 -F test/stat.test c7b20ea43003dc2dc33335e231c27be8284c4a2a +F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 +F test/stat.test 36bc951bdc2beac4224cc54396fd6a7dc65336f4 F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796 +F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a -F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082 -F test/sync.test 2bd73b585089c99e76b3e1796c42059b7d89d872 -F test/syscall.test 707c95e4ab7863e13f1293c6b0c76bead30249b3 +F test/superlock.test 7b1167925e9d30a5d1f0701d24812fdda42c3a86 +F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 +F test/syscall.test 966addf703faee6a5d509abe6d8885e393e552fd F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f -F test/table.test 04ba066432430657712d167ebf28080fe878d305 +F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 -F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3 +F test/tclsqlite.test 5ebcbb0dccc3fbc1edc3bba84c38e2c2d574c5aa F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c -F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a -F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05 -F test/tester.tcl 7d3d17914ca5397a82f801db733b81d4a82f50c3 -F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f -F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db -F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca +F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2 +F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d +F test/tester.tcl 0b2999b578964297663de4870babbbee29225622 +F test/thread001.test 7cc2ce08f9cde95964736d11e91f9ab610f82f91 +F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 +F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 F test/thread004.test f51dfc3936184aaf73ee85f315224baad272a87f -F test/thread005.test bf5c374ca65dd89fd56c8fe511ccfb46875bda5e +F test/thread005.test 50d10b5684399676174bd96c94ad4250b1a2c8b6 F test/thread1.test df115faa10a4ba1d456e9d4d9ec165016903eae4 F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd @@ -709,17 +721,18 @@ F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef F test/tkt-02a8e81d44.test 58494de77be2cf249228ada3f313fa399821c6ab F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 -F test/tkt-2d1a5c67d.test 73574c758502bf23260c17f97fcd9316dfb5a060 +F test/tkt-2d1a5c67d.test b028a811049eb472cb2d3a43fc8ce4f6894eebda F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 -F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e +F test/tkt-31338dca7e.test 1f714c14b6682c5db715e0bda347926a3456f7a9 F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac F test/tkt-38cb5df375.test 9e9b19857dba0896a8efdaf334d405ba423492f2 F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7 F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00 F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e +F test/tkt-54844eea3f.test a12b851128f46a695e4e378cca67409b9b8f5894 F test/tkt-5d863f876e.test 884072c2de496ddbb90c387c9ebc0d4f44a91b8e F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84 -F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9 +F test/tkt-5ee23731f.test 9db6e1d7209dc0794948b260d6f82b2b1de83a9f F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf F test/tkt-78e04e52ea.test ab52f0c1e2de6e46c910f4cc16b086bba05952b7 F test/tkt-80ba201079.test a09684db1a0bd55b8838f606adccee456a51ddbf @@ -728,16 +741,20 @@ F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5 F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67 +F test/tkt-b1d3a2e531.test 610ef582413171b379652663111b1f996d9f8f78 F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0 F test/tkt-b72787b1.test e6b62b2b2785c04d0d698d6a603507e384165049 F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898 -F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589 +F test/tkt-c48d99d690.test bed446e3513ae10eec1b86fdd186ef750226c408 +F test/tkt-cbd054fa6b.test bd9fb546f63bc0c79d1776978d059fa51c5b1c63 F test/tkt-d11f09d36e.test fb44f7961aa6d4b632fb7b9768239832210b5fc7 +F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09 F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6 -F test/tkt-f3e5abed55.test 19fb59268da6f20a69a181b9c14154132d1c65e3 +F test/tkt-f3e5abed55.test 669bb076f2ac573c7398ce00f40cd0ca502043a9 F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87 F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7 F test/tkt-f973c7ac31.test 1da0ed15ec2c7749fb5ce2828cd69d07153ad9f4 +F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035 F test/tkt-fc62af4523.test 72825d3febdedcd5593a27989fc05accdbfc2bb4 F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00 F test/tkt1443.test bacc311da5c96a227bf8c167e77a30c99f8e8368 @@ -751,8 +768,8 @@ F test/tkt1536.test 83ff7a7b6e248016f8d682d4f7a4ae114070d466 F test/tkt1537.test e3a14332de9770be8ff14bd15c19a49cbec10808 F test/tkt1567.test 18023cc3626a365f0118e17b66decedec93b1a6f F test/tkt1644.test 80b6a2bb17885f3cf1cb886d97cdad13232bb869 -F test/tkt1667.test 5d208e8d8cbcf82a446b315774290b66b464bc5f -F test/tkt1873.test 255a002b9afdcf8b0fa3188984e2c964202340e9 +F test/tkt1667.test 4700d931ed19ea3983e8e703becb28079250b460 +F test/tkt1873.test 0e1b8c023050a430c2525179ed4022ddc7c31264 F test/tkt2141.test f543d96f50d5a5dc0bc744f7db74ea166720ce46 F test/tkt2192.test ff40157e5f42e65f844255d220fc6b290470942f F test/tkt2213.test a9702175601a57b61aba095a233b001d6f362474 @@ -766,13 +783,13 @@ F test/tkt2450.test 77ed94863f2049c1420288ddfea2d41e5e0971d6 F test/tkt2565.test 8be666e927cb207aae88188f31c331870878b650 F test/tkt2640.test 28134f5d1e05658ef182520cf0b680fa3de5211b F test/tkt2643.test 3f3ebb743da00d4fed4fcf6daed92a0e18e57813 -F test/tkt2686.test 08f0f584461bc4990376936daa0a9bd3e6e81671 +F test/tkt2686.test 6ee01c9b9e9c48f6d3a1fdd553b1cc4258f903d6 F test/tkt2767.test 569000d842678f9cf2db7e0d1b27cbc9011381b0 -F test/tkt2817.test 94646b604c7dbae7058782f6582c05e200700aa9 -F test/tkt2820.test 017fdee33aaef7abc092beab6088816f1942304b +F test/tkt2817.test f31839e01f4243cff7399ef654d3af3558cb8d8d +F test/tkt2820.test 39940276b3436d125deb7d8ebeee053e4cf13213 F test/tkt2822.test a2b27a58df62d1b2e712f91dbe42ad3b7e0e77cc F test/tkt2832.test a9b0b74a02dca166a04d9e37739c414b10929caa -F test/tkt2854.test b81dc3144901b123fe5674471adf5a47ca48a7c3 +F test/tkt2854.test e432965db29e27e16f539b2ba7f502eb2ccc49af F test/tkt2920.test a8737380e4ae6424e00c0273dc12775704efbebf F test/tkt2927.test 4752868b9eeeb07a217f7f19f4cbaac98d6d086d F test/tkt2942.test c5c87d179799ca6d1fbe83c815510b87cd5ec7ce @@ -788,7 +805,7 @@ F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812 F test/tkt3442.test 0adb70e9fe9cb750a702065a68ad647409dbc158 -F test/tkt3457.test edbf54b05cbe5165f00192becbd621038f1615e4 +F test/tkt3457.test eb68bb3b19c8677cff06c639ff15d206dbf17fd6 F test/tkt3461.test 228ea328a5a21e8663f80ee3d212a6ad92549a19 F test/tkt3493.test 1686cbde85f8721fc1bdc0ee72f2ef2f63139218 F test/tkt3508.test d75704db9501625c7f7deec119fcaf1696aefb7d @@ -797,7 +814,7 @@ F test/tkt3527.test ee4af96183579565987e58873a7490bc04934ffb F test/tkt3541.test 5dc257bde9bc833ab9cc6844bf170b998dbb950a F test/tkt3554.test f599967f279077bace39220cbe76085c7b423725 F test/tkt3581.test 1966b7193f1e3f14951cce8c66907ae69454e9a3 -F test/tkt35xx.test ed9721bd9eb1693b3b4d3cf2a093fa7f92af0c93 +F test/tkt35xx.test 69d038ce5898f1b64f2084b780bbab1cf9be0a25 F test/tkt3630.test 929f64852103054125200bc825c316d5f75d42f7 F test/tkt3718.test 3b59dcb5c4e7754dacd91e7fd353a61492cc402a F test/tkt3731.test 0c5f4cbffe102d43c3b2188af91a9e36348f974b @@ -806,7 +823,7 @@ F test/tkt3761.test b95ea9c98f21cf91325f18a984887e62caceab33 F test/tkt3762.test 2a9f3b03df44ec49ec0cfa8d5da6574c2a7853df F test/tkt3773.test 430b06567ce40285dfd2c4834a2a61816403efeb F test/tkt3791.test a6624b9a80b216a26cf473607f42f3e51898c267 -F test/tkt3793.test 754b73f0e6a9349c70dc57e522cf3247272ecd5d +F test/tkt3793.test d90ffd75c52413908d15e1c44fc2ea9c80fcc449 F test/tkt3810.test 90fa0635dfa7da9680c8cd3513350a49b3a8ae12 F test/tkt3824.test 150aa00bb6220672e5f0eb14dc8eaa36750425f0 F test/tkt3832.test 2300d10d57562b89875b72148338ac3e14f8847d @@ -828,103 +845,109 @@ F test/trace2.test 962175290996d5f06dc4402ca218bbfc7df4cb20 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22 F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97 -F test/trigger1.test 2e18561f85e448bb633c9c9de792e9bbf7b2dd3e +F test/trigger1.test 38c657eaf9907344c9e0bcb16af94a452c6babde F test/trigger2.test 834187beafd1db383af0c659cfa49b0576832816 F test/trigger3.test d2c60d8be271c355d61727411e753181e877230a -F test/trigger4.test 8e90ee98cba940cd5f96493f82e55083806ab8a0 +F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359 F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83 F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9 F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4 F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31 -F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e +F test/triggerA.test e0aaba16d3547193d36bbd82a1b0ed75e9c88d40 F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe -F test/triggerC.test 02c690febf608ae20b9af86184a9867f79855b1d -F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7 +F test/triggerC.test 4d4bdaf0230c206b50d350330107ef9802bc2d4f +F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650 F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2 F test/unixexcl.test 9d80a54d86d2261f660758928959368ffc36151e -F test/unordered.test e81169ce2a8f31b2c6b66af691887e1376ab3ced +F test/unordered.test f53095cee37851bf30130fa1bf299a8845e837bb F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172 -F test/uri.test 53de9a2549cbda9c343223236918ef502f6a9051 +F test/uri.test 0d289d32396bdbc491e9dc845f1a52e13f861e0b F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae -F test/vacuum.test 29b60e8cc9e573b39676df6c4a75fe9e02d04a09 -F test/vacuum2.test 91a84c9b08adfc4472097d2e8deb0150214e0e76 -F test/vacuum3.test f39ad1428347c5808cd2da7578c470f186a4d0ce +F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d +F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324 +F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b -F test/view.test 45f518205ecdb6dd23a86dd4a99bb4ae945e625d -F test/vtab1.test 7b79832824cbae37ff01a06ed155027f7c15bf9e +F test/view.test b182a67ec43f490b156b5a710827a341be83dd17 +F test/vtab1.test 12fbb309ce830c4064e44f275eb02a65c2780076 F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1 F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391 F test/vtab6.test c7f290d172609d636fbfc58166eadcb55d5c117c -F test/vtab7.test a8c3c3cb3eb60be364991bd714e4927e26c4cd85 +F test/vtab7.test ae560ebea870ed04e9aa4177cc302f910faaabb5 F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b F test/vtabA.test c86e1990b7e1e2bb34602a06fffa4c69f2b516dc F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796 -F test/vtabC.test 1cf7896ab6859bfe3074244b2b0e12de5cbdd766 +F test/vtabC.test 4528f459a13136f982e75614d120aef165f17292 F test/vtabD.test 74167b1578e5886fe4c886d6bef2fd1406444c42 F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61 +F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d -F test/wal.test 5617ad308bfdb8a8885220d8a261a6096a8d7e57 -F test/wal2.test aa0fb2314b3235be4503c06873e41ebfc0757782 -F test/wal3.test 5c396cc22497244d627306f4c1d360167353f8dd -F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30 -F test/wal5.test f06a0427e06db00347e32eb9fa99d6a5c0f2d088 -F test/wal6.test 07aa31ca8892d0527f2c5c5a9a2a87aa421dfaa8 +F test/wal.test e11da8d5ea8a38a247339455098357e9adf63d76 +F test/wal2.test ad6412596815f553cd30f271d291ab003092bc7e +F test/wal3.test 18da4e65c30c43c646ad40e145e9a074e4062fc9 +F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c +F test/wal5.test 1bbfaa316dc2a1d0d1fac3f4500c38a90055a41b +F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3 F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe -F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4 -F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0 -F test/walcksum.test a37b36375c595e61bdb7e1ec49b5f0979b6fc7ce -F test/walcrash.test e763841551d6b23677ccb419797c1589dcbdbaf5 +F test/walbak.test b9f68e39646375c2b877be906babcc15d38b4877 +F test/walbig.test 0ab8a430ef420a3114f7092e0f30fc9585ffa155 +F test/walcksum.test f5447800a157c9e2234fbb8e80243f0813941bde +F test/walcrash.test 4fcb661faf71db91214156d52d43ee327f52bde1 F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142 -F test/walfault.test 58fce626359c9376fe35101b5c0f2df8040aa839 +F test/walfault.test efb0d5724893133e71b8d9d90abdb781845a6bb0 F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483 -F test/walmode.test 22ddccd073c817ac9ead62b88ac446e8dedc7d2c -F test/walnoshm.test a074428046408f4eb5c6a00e09df8cc97ff93317 -F test/walro.test 2d5d69e2e99da19ce6faab340330234fc4ca0720 +F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c +F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496 +F test/walpersist.test fd40d33765b2693f721c90c66d97f99757559006 +F test/walro.test e6bb27762c9f22601cbb8bff6e0acfd124e74b63 F test/walshared.test 6dda2293880c300baf5d791c307f653094585761 -F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933 -F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c +F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a +F test/walthread.test a2ed5270eb695284d4ad27d252517bdc3317ee2a F test/where.test de337a3fe0a459ec7c93db16a519657a90552330 F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554 -F test/where3.test 8e1175c7ef710c70502858fc4fb08d784b3620b9 +F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b -F test/where7.test aa4cfcd6f66e2a4ef87b6717327325bf4d547502 +F test/where7.test 814d7373413398e074f134cff5f8872e2c08bd3b F test/where8.test a6c740fd286d7883e274e17b6230a9d672a7ab1f F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 -F test/where9.test 24f19ad14bb1b831564ced5273e681e495662848 +F test/where9.test bed66dcfc69a54a99661c0c9906189cb5e58f4e2 F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 +F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b +F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c d51c68d405ff7f9bad99268ca3c20a198eb983ed +F tool/lemon.c 949328f67cac94969d3112b105b8457edf27f44e F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 -F tool/mksqlite3c.tcl 1fa0ed9cfdc768bf5de7e65fda8d97a46dd2a7e6 +F tool/mksqlite3c-noext.tcl 105023aa86f696a74b1d6a4929d1e1c3baf9471c +F tool/mksqlite3c.tcl 9fbac513cd9d5ac95ad55630f49bb16c5347ab75 F tool/mksqlite3h.tcl 78013ad79a5e492e5f764f3c7a8ef834255061f8 F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87 -F tool/omittest.tcl 8086c014cbae90f1f2b564d59d05a5e4ac1783c9 +F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091 +F tool/omittest.tcl 72a49b8a9a8b0bf213a438180307a0df836d4380 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 @@ -938,18 +961,21 @@ F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02 F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9 F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b -F tool/spaceanal.tcl b91879d52bf77a1ff5382493284f429d32a63490 +F tool/spaceanal.tcl 15f6cd939b4ecc14d061de7e8ace89e26c30c40b 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/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c -F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00 -F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576 +F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d +F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f +F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d -P de8ad5f8176d5573c02ec39b14cca324cfef5cb9 -R 627b3b91e5169f5233cd18fa7efa5202 -U dan -Z 94b0ac9079eaca2f6ca6db06cfa18fd2 +F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a +F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 +P 6635cd9a7714b681dd8aa96e90be462a40d10178 +R b059ff356abfc5b4524a9b548916f43e +T +sym-version-3.7.9 * +U drh +Z a9ecbb5c487c786a176874d979505217 diff --git a/manifest.uuid b/manifest.uuid index 735e9cae..cf01f92c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -af0d91adf497f5f36ec3813f04235a6e195a605f +c7c6050ef060877ebe77b41d959e9df13f8c9b5e diff --git a/mkopcodec.awk b/mkopcodec.awk index ec809530..2ef77d4c 100644 --- a/mkopcodec.awk +++ b/mkopcodec.awk @@ -17,13 +17,18 @@ BEGIN { print " || defined(SQLITE_DEBUG)" print "const char *sqlite3OpcodeName(int i){" print " static const char *const azName[] = { \"?\"," + mx = 0 } /define OP_/ { sub("OP_","",$2) - i++ - printf " /* %3d */ \"%s\",\n", $3, $2 + i = $3+0 + label[i] = $2 + if( mx1) is the average number of rows in +** the index which have the same value for the first N-1 columns. For +** a K-column index, there will be K+1 integers in the stat column. If +** the index is unique, then the last integer will be 1. +** +** The list of integers in the stat column can optionally be followed +** by the keyword "unordered". The "unordered" keyword, if it is present, +** must be separated from the last integer by a single space. If the +** "unordered" keyword is present, then the query planner assumes that +** the index is unordered and will not use the index for a range query. +** +** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat +** column contains a single integer which is the (estimated) number of +** rows in the table identified by sqlite_stat1.tbl. +** +** Format of sqlite_stat2: +** +** The sqlite_stat2 is only created and is only used if SQLite is compiled +** with SQLITE_ENABLE_STAT2 and if the SQLite version number is between +** 3.6.18 and 3.7.8. The "stat2" table contains additional information +** about the distribution of keys within an index. The index is identified by +** the "idx" column and the "tbl" column is the name of the table to which +** the index belongs. There are usually 10 rows in the sqlite_stat2 +** table for each index. +** +** The sqlite_stat2 entries for an index that have sampleno between 0 and 9 +** inclusive are samples of the left-most key value in the index taken at +** evenly spaced points along the index. Let the number of samples be S +** (10 in the standard build) and let C be the number of rows in the index. +** Then the sampled rows are given by: +** +** rownumber = (i*C*2 + C)/(S*2) +** +** For i between 0 and S-1. Conceptually, the index space is divided into +** S uniform buckets and the samples are the middle row from each bucket. +** +** The format for sqlite_stat2 is recorded here for legacy reference. This +** version of SQLite does not support sqlite_stat2. It neither reads nor +** writes the sqlite_stat2 table. This version of SQLite only supports +** sqlite_stat3. +** +** Format for sqlite_stat3: +** +** The sqlite_stat3 is an enhancement to sqlite_stat2. A new name is +** used to avoid compatibility problems. +** +** The format of the sqlite_stat3 table is similar to the format of +** the sqlite_stat2 table. There are multiple entries for each index. +** The idx column names the index and the tbl column is the table of the +** index. If the idx and tbl columns are the same, then the sample is +** of the INTEGER PRIMARY KEY. The sample column is a value taken from +** the left-most column of the index. The nEq column is the approximate +** number of entires in the index whose left-most column exactly matches +** the sample. nLt is the approximate number of entires whose left-most +** column is less than the sample. The nDLt column is the approximate +** number of distinct left-most entries in the index that are less than +** the sample. +** +** Future versions of SQLite might change to store a string containing +** multiple integers values in the nDLt column of sqlite_stat3. The first +** integer will be the number of prior index entires that are distinct in +** the left-most column. The second integer will be the number of prior index +** entries that are distinct in the first two columns. The third integer +** will be the number of prior index entries that are distinct in the first +** three columns. And so forth. With that extension, the nDLt field is +** similar in function to the sqlite_stat1.stat field. +** +** There can be an arbitrary number of sqlite_stat3 entries per index. +** The ANALYZE command will typically generate sqlite_stat3 tables +** that contain between 10 and 40 samples which are distributed across +** the key space, though not uniformly, and which include samples with +** largest possible nEq values. */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -17,16 +119,16 @@ /* ** This routine generates code that opens the sqlite_stat1 table for ** writing with cursor iStatCur. If the library was built with the -** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is +** SQLITE_ENABLE_STAT3 macro defined, then the sqlite_stat3 table is ** opened for writing using cursor (iStatCur+1) ** ** If the sqlite_stat1 tables does not previously exist, it is created. -** Similarly, if the sqlite_stat2 table does not exist and the library -** is compiled with SQLITE_ENABLE_STAT2 defined, it is created. +** Similarly, if the sqlite_stat3 table does not exist and the library +** is compiled with SQLITE_ENABLE_STAT3 defined, it is created. ** ** Argument zWhere may be a pointer to a buffer containing a table name, ** or it may be a NULL pointer. If it is not NULL, then all entries in -** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated +** the sqlite_stat1 and (if applicable) sqlite_stat3 tables associated ** with the named table are deleted. If zWhere==0, then code is generated ** to delete all stat table entries. */ @@ -42,8 +144,8 @@ static void openStatTable( const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, -#ifdef SQLITE_ENABLE_STAT2 - { "sqlite_stat2", "tbl,idx,sampleno,sample" }, +#ifdef SQLITE_ENABLE_STAT3 + { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" }, #endif }; @@ -59,6 +161,9 @@ static void openStatTable( assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; + /* Create new statistic tables if they do not exist, or clear them + ** if they do already exist. + */ for(i=0; ia[0])*mxSample; + p = sqlite3_malloc( n ); + if( p==0 ){ + sqlite3_result_error_nomem(context); + return; + } + memset(p, 0, n); + p->a = (struct Stat3Sample*)&p[1]; + p->nRow = nRow; + p->mxSample = mxSample; + p->nPSample = p->nRow/(mxSample/3+1) + 1; + sqlite3_randomness(sizeof(p->iPrn), &p->iPrn); + sqlite3_result_blob(context, p, sizeof(p), sqlite3_free); +} +static const FuncDef stat3InitFuncdef = { + 2, /* nArg */ + SQLITE_UTF8, /* iPrefEnc */ + 0, /* flags */ + 0, /* pUserData */ + 0, /* pNext */ + stat3Init, /* xFunc */ + 0, /* xStep */ + 0, /* xFinalize */ + "stat3_init", /* zName */ + 0, /* pHash */ + 0 /* pDestructor */ +}; + + +/* +** Implementation of the stat3_push(nEq,nLt,nDLt,rowid,P) SQL function. The +** arguments describe a single key instance. This routine makes the +** decision about whether or not to retain this key for the sqlite_stat3 +** table. +** +** The return value is NULL. +*/ +static void stat3Push( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Stat3Accum *p = (Stat3Accum*)sqlite3_value_blob(argv[4]); + tRowcnt nEq = sqlite3_value_int64(argv[0]); + tRowcnt nLt = sqlite3_value_int64(argv[1]); + tRowcnt nDLt = sqlite3_value_int64(argv[2]); + i64 rowid = sqlite3_value_int64(argv[3]); + u8 isPSample = 0; + u8 doInsert = 0; + int iMin = p->iMin; + struct Stat3Sample *pSample; + int i; + u32 h; + + UNUSED_PARAMETER(context); + UNUSED_PARAMETER(argc); + if( nEq==0 ) return; + h = p->iPrn = p->iPrn*1103515245 + 12345; + if( (nLt/p->nPSample)!=((nEq+nLt)/p->nPSample) ){ + doInsert = isPSample = 1; + }else if( p->nSamplemxSample ){ + doInsert = 1; + }else{ + if( nEq>p->a[iMin].nEq || (nEq==p->a[iMin].nEq && h>p->a[iMin].iHash) ){ + doInsert = 1; + } + } + if( !doInsert ) return; + if( p->nSample==p->mxSample ){ + assert( p->nSample - iMin - 1 >= 0 ); + memmove(&p->a[iMin], &p->a[iMin+1], sizeof(p->a[0])*(p->nSample-iMin-1)); + pSample = &p->a[p->nSample-1]; + }else{ + pSample = &p->a[p->nSample++]; + } + pSample->iRowid = rowid; + pSample->nEq = nEq; + pSample->nLt = nLt; + pSample->nDLt = nDLt; + pSample->iHash = h; + pSample->isPSample = isPSample; + + /* Find the new minimum */ + if( p->nSample==p->mxSample ){ + pSample = p->a; + i = 0; + while( pSample->isPSample ){ + i++; + pSample++; + assert( inSample ); + } + nEq = pSample->nEq; + h = pSample->iHash; + iMin = i; + for(i++, pSample++; inSample; i++, pSample++){ + if( pSample->isPSample ) continue; + if( pSample->nEqnEq==nEq && pSample->iHashnEq; + h = pSample->iHash; + } + } + p->iMin = iMin; + } +} +static const FuncDef stat3PushFuncdef = { + 5, /* nArg */ + SQLITE_UTF8, /* iPrefEnc */ + 0, /* flags */ + 0, /* pUserData */ + 0, /* pNext */ + stat3Push, /* xFunc */ + 0, /* xStep */ + 0, /* xFinalize */ + "stat3_push", /* zName */ + 0, /* pHash */ + 0 /* pDestructor */ +}; + +/* +** Implementation of the stat3_get(P,N,...) SQL function. This routine is +** used to query the results. Content is returned for the Nth sqlite_stat3 +** row where N is between 0 and S-1 and S is the number of samples. The +** value returned depends on the number of arguments. +** +** argc==2 result: rowid +** argc==3 result: nEq +** argc==4 result: nLt +** argc==5 result: nDLt +*/ +static void stat3Get( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int n = sqlite3_value_int(argv[1]); + Stat3Accum *p = (Stat3Accum*)sqlite3_value_blob(argv[0]); + + assert( p!=0 ); + if( p->nSample<=n ) return; + switch( argc ){ + case 2: sqlite3_result_int64(context, p->a[n].iRowid); break; + case 3: sqlite3_result_int64(context, p->a[n].nEq); break; + case 4: sqlite3_result_int64(context, p->a[n].nLt); break; + default: sqlite3_result_int64(context, p->a[n].nDLt); break; + } +} +static const FuncDef stat3GetFuncdef = { + -1, /* nArg */ + SQLITE_UTF8, /* iPrefEnc */ + 0, /* flags */ + 0, /* pUserData */ + 0, /* pNext */ + stat3Get, /* xFunc */ + 0, /* xStep */ + 0, /* xFinalize */ + "stat3_get", /* zName */ + 0, /* pHash */ + 0 /* pDestructor */ +}; +#endif /* SQLITE_ENABLE_STAT3 */ + + + + /* ** Generate code to do an analysis of all indices associated with ** a single table. @@ -119,20 +444,27 @@ static void analyzeOneTable( int iDb; /* Index of database containing pTab */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ - int regSampleno = iMem++; /* Register containing next sample number */ - int regCol = iMem++; /* Content of a column analyzed table */ + int regStat1 = iMem++; /* The stat column of sqlite_stat1 */ +#ifdef SQLITE_ENABLE_STAT3 + int regNumEq = regStat1; /* Number of instances. Same as regStat1 */ + int regNumLt = iMem++; /* Number of keys less than regSample */ + int regNumDLt = iMem++; /* Number of distinct keys less than regSample */ + int regSample = iMem++; /* The next sample value */ + int regRowid = regSample; /* Rowid of a sample */ + int regAccum = iMem++; /* Register to hold Stat3Accum object */ + int regLoop = iMem++; /* Loop counter */ + int regCount = iMem++; /* Number of rows in the table or index */ + int regTemp1 = iMem++; /* Intermediate register */ + int regTemp2 = iMem++; /* Intermediate register */ + int once = 1; /* One-time initialization */ + int shortJump = 0; /* Instruction address */ + int iTabCur = pParse->nTab++; /* Table cursor */ +#endif + int regCol = iMem++; /* Content of a column in analyzed table */ int regRec = iMem++; /* Register holding completed record */ int regTemp = iMem++; /* Temporary use register */ - int regRowid = iMem++; /* Rowid for the inserted record */ + int regNewRowid = iMem++; /* Rowid for the inserted record */ -#ifdef SQLITE_ENABLE_STAT2 - int addr = 0; /* Instruction address */ - int regTemp2 = iMem++; /* Temporary use register */ - int regSamplerecno = iMem++; /* Index of next sample to record */ - int regRecno = iMem++; /* Current sample index */ - int regLast = iMem++; /* Index of last sample to record */ - int regFirst = iMem++; /* Index of first sample to record */ -#endif v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ @@ -165,9 +497,14 @@ static void analyzeOneTable( for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol; KeyInfo *pKey; + int addrIfNot = 0; /* address of OP_IfNot */ + int *aChngAddr; /* Array of jump instruction addresses */ if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; + VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName)); nCol = pIdx->nColumn; + aChngAddr = sqlite3DbMallocRaw(db, sizeof(int)*nCol); + if( aChngAddr==0 ) continue; pKey = sqlite3IndexKeyinfo(pParse, pIdx); if( iMem+1+(nCol*2)>pParse->nMem ){ pParse->nMem = iMem+1+(nCol*2); @@ -182,31 +519,20 @@ static void analyzeOneTable( /* Populate the register containing the index name. */ sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0); -#ifdef SQLITE_ENABLE_STAT2 - - /* If this iteration of the loop is generating code to analyze the - ** first index in the pTab->pIndex list, then register regLast has - ** not been populated. In this case populate it now. */ - if( pTab->pIndex==pIdx ){ - sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES, regSamplerecno); - sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES*2-1, regTemp); - sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES*2, regTemp2); - - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regLast); - sqlite3VdbeAddOp2(v, OP_Null, 0, regFirst); - addr = sqlite3VdbeAddOp3(v, OP_Lt, regSamplerecno, 0, regLast); - sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regLast, regFirst); - sqlite3VdbeAddOp3(v, OP_Multiply, regLast, regTemp, regLast); - sqlite3VdbeAddOp2(v, OP_AddImm, regLast, SQLITE_INDEX_SAMPLES*2-2); - sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regLast, regLast); - sqlite3VdbeJumpHere(v, addr); +#ifdef SQLITE_ENABLE_STAT3 + if( once ){ + once = 0; + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); } - - /* Zero the regSampleno and regRecno registers. */ - sqlite3VdbeAddOp2(v, OP_Integer, 0, regSampleno); - sqlite3VdbeAddOp2(v, OP_Integer, 0, regRecno); - sqlite3VdbeAddOp2(v, OP_Copy, regFirst, regSamplerecno); -#endif + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regCount); + sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_STAT3_SAMPLES, regTemp1); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumEq); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumLt); + sqlite3VdbeAddOp2(v, OP_Integer, -1, regNumDLt); + sqlite3VdbeAddOp4(v, OP_Function, 1, regCount, regAccum, + (char*)&stat3InitFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 2); +#endif /* SQLITE_ENABLE_STAT3 */ /* The block of memory cells initialized here is used as follows. ** @@ -236,75 +562,83 @@ static void analyzeOneTable( endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1); + sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1); /* Increment row counter */ for(i=0; iazColl!=0 ); assert( pIdx->azColl[i]!=0 ); pColl = sqlite3LocateCollSeq(pParse, pIdx->azColl[i]); - sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1, - (char*)pColl, P4_COLLSEQ); + aChngAddr[i] = sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1, + (char*)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - } - if( db->mallocFailed ){ - /* If a malloc failure has occurred, then the result of the expression - ** passed as the second argument to the call to sqlite3VdbeJumpHere() - ** below may be negative. Which causes an assert() to fail (or an - ** out-of-bounds write if SQLITE_DEBUG is not defined). */ - return; + VdbeComment((v, "jump if column %d changed", i)); +#ifdef SQLITE_ENABLE_STAT3 + if( i==0 ){ + sqlite3VdbeAddOp2(v, OP_AddImm, regNumEq, 1); + VdbeComment((v, "incr repeat count")); + } +#endif } sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop); for(i=0; inColumn, regRowid); + sqlite3VdbeAddOp3(v, OP_Add, regNumEq, regNumLt, regNumLt); + sqlite3VdbeAddOp2(v, OP_AddImm, regNumDLt, 1); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regNumEq); +#endif } - sqlite3VdbeJumpHere(v, addr2); /* Set jump dest for the OP_Ne */ sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1); } + sqlite3DbFree(db, aChngAddr); - /* End of the analysis loop. */ + /* Always jump here after updating the iMem+1...iMem+1+nCol counters */ sqlite3VdbeResolveLabel(v, endOfLoop); + sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); +#ifdef SQLITE_ENABLE_STAT3 + sqlite3VdbeAddOp4(v, OP_Function, 1, regNumEq, regTemp2, + (char*)&stat3PushFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 5); + sqlite3VdbeAddOp2(v, OP_Integer, -1, regLoop); + shortJump = + sqlite3VdbeAddOp2(v, OP_AddImm, regLoop, 1); + sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regTemp1, + (char*)&stat3GetFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 2); + sqlite3VdbeAddOp1(v, OP_IsNull, regTemp1); + sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, shortJump, regTemp1); + sqlite3VdbeAddOp3(v, OP_Column, iTabCur, pIdx->aiColumn[0], regSample); + sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[0], regSample); + sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regNumEq, + (char*)&stat3GetFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 3); + sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regNumLt, + (char*)&stat3GetFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 4); + sqlite3VdbeAddOp4(v, OP_Function, 1, regAccum, regNumDLt, + (char*)&stat3GetFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 5); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 6, regRec, "bbbbbb", 0); + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regRec, regNewRowid); + sqlite3VdbeAddOp2(v, OP_Goto, 0, shortJump); + sqlite3VdbeJumpHere(v, shortJump+2); +#endif /* Store the results in sqlite_stat1. ** @@ -324,22 +658,22 @@ static void analyzeOneTable( ** If K>0 then it is always the case the D>0 so division by zero ** is never possible. */ - sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno); + sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regStat1); if( jZeroRows<0 ){ jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); } for(i=0; ipIndex==0 ){ sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb); VdbeComment((v, "%s", pTab->zName)); - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regSampleno); + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat1); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); - jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regSampleno); + jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); }else{ sqlite3VdbeJumpHere(v, jZeroRows); jZeroRows = sqlite3VdbeAddOp0(v, OP_Goto); } sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); - sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid); + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); if( pParse->nMemnMem = regRec; sqlite3VdbeJumpHere(v, jZeroRows); } + /* ** Generate code that will cause the most recent index analysis to ** be loaded into internal hash tables where is can be used. @@ -388,7 +723,7 @@ static void analyzeDatabase(Parse *pParse, int iDb){ sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; - pParse->nTab += 2; + pParse->nTab += 3; openStatTable(pParse, iDb, iStatCur, 0, 0); iMem = pParse->nMem+1; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); @@ -413,7 +748,7 @@ static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; - pParse->nTab += 2; + pParse->nTab += 3; if( pOnlyIdx ){ openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx"); }else{ @@ -518,7 +853,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ Index *pIndex; Table *pTable; int i, c, n; - unsigned int v; + tRowcnt v; const char *z; assert( argc==3 ); @@ -561,10 +896,10 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ ** and its contents. */ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 if( pIdx->aSample ){ int j; - for(j=0; jnSample; j++){ IndexSample *p = &pIdx->aSample[j]; if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){ sqlite3DbFree(db, p->u.z); @@ -572,25 +907,157 @@ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ } sqlite3DbFree(db, pIdx->aSample); } + if( db && db->pnBytesFreed==0 ){ + pIdx->nSample = 0; + pIdx->aSample = 0; + } #else UNUSED_PARAMETER(db); UNUSED_PARAMETER(pIdx); #endif } +#ifdef SQLITE_ENABLE_STAT3 /* -** Load the content of the sqlite_stat1 and sqlite_stat2 tables. The +** Load content from the sqlite_stat3 table into the Index.aSample[] +** arrays of all indices. +*/ +static int loadStat3(sqlite3 *db, const char *zDb){ + int rc; /* Result codes from subroutines */ + sqlite3_stmt *pStmt = 0; /* An SQL statement being run */ + char *zSql; /* Text of the SQL statement */ + Index *pPrevIdx = 0; /* Previous index in the loop */ + int idx = 0; /* slot in pIdx->aSample[] for next sample */ + int eType; /* Datatype of a sample */ + IndexSample *pSample; /* A slot in pIdx->aSample[] */ + + if( !sqlite3FindTable(db, "sqlite_stat3", zDb) ){ + return SQLITE_OK; + } + + zSql = sqlite3MPrintf(db, + "SELECT idx,count(*) FROM %Q.sqlite_stat3" + " GROUP BY idx", zDb); + if( !zSql ){ + return SQLITE_NOMEM; + } + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + sqlite3DbFree(db, zSql); + if( rc ) return rc; + + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + char *zIndex; /* Index name */ + Index *pIdx; /* Pointer to the index object */ + int nSample; /* Number of samples */ + + zIndex = (char *)sqlite3_column_text(pStmt, 0); + if( zIndex==0 ) continue; + nSample = sqlite3_column_int(pStmt, 1); + pIdx = sqlite3FindIndex(db, zIndex, zDb); + if( pIdx==0 ) continue; + assert( pIdx->nSample==0 ); + pIdx->nSample = nSample; + pIdx->aSample = sqlite3MallocZero( nSample*sizeof(IndexSample) ); + pIdx->avgEq = pIdx->aiRowEst[1]; + if( pIdx->aSample==0 ){ + db->mallocFailed = 1; + sqlite3_finalize(pStmt); + return SQLITE_NOMEM; + } + } + rc = sqlite3_finalize(pStmt); + if( rc ) return rc; + + zSql = sqlite3MPrintf(db, + "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat3", zDb); + if( !zSql ){ + return SQLITE_NOMEM; + } + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + sqlite3DbFree(db, zSql); + if( rc ) return rc; + + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + char *zIndex; /* Index name */ + Index *pIdx; /* Pointer to the index object */ + int i; /* Loop counter */ + tRowcnt sumEq; /* Sum of the nEq values */ + + zIndex = (char *)sqlite3_column_text(pStmt, 0); + if( zIndex==0 ) continue; + pIdx = sqlite3FindIndex(db, zIndex, zDb); + if( pIdx==0 ) continue; + if( pIdx==pPrevIdx ){ + idx++; + }else{ + pPrevIdx = pIdx; + idx = 0; + } + assert( idxnSample ); + pSample = &pIdx->aSample[idx]; + pSample->nEq = (tRowcnt)sqlite3_column_int64(pStmt, 1); + pSample->nLt = (tRowcnt)sqlite3_column_int64(pStmt, 2); + pSample->nDLt = (tRowcnt)sqlite3_column_int64(pStmt, 3); + if( idx==pIdx->nSample-1 ){ + if( pSample->nDLt>0 ){ + for(i=0, sumEq=0; i<=idx-1; i++) sumEq += pIdx->aSample[i].nEq; + pIdx->avgEq = (pSample->nLt - sumEq)/pSample->nDLt; + } + if( pIdx->avgEq<=0 ) pIdx->avgEq = 1; + } + eType = sqlite3_column_type(pStmt, 4); + pSample->eType = (u8)eType; + switch( eType ){ + case SQLITE_INTEGER: { + pSample->u.i = sqlite3_column_int64(pStmt, 4); + break; + } + case SQLITE_FLOAT: { + pSample->u.r = sqlite3_column_double(pStmt, 4); + break; + } + case SQLITE_NULL: { + break; + } + default: assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); { + const char *z = (const char *)( + (eType==SQLITE_BLOB) ? + sqlite3_column_blob(pStmt, 4): + sqlite3_column_text(pStmt, 4) + ); + int n = z ? sqlite3_column_bytes(pStmt, 4) : 0; + pSample->nByte = n; + if( n < 1){ + pSample->u.z = 0; + }else{ + pSample->u.z = sqlite3Malloc(n); + if( pSample->u.z==0 ){ + db->mallocFailed = 1; + sqlite3_finalize(pStmt); + return SQLITE_NOMEM; + } + memcpy(pSample->u.z, z, n); + } + } + } + } + return sqlite3_finalize(pStmt); +} +#endif /* SQLITE_ENABLE_STAT3 */ + +/* +** Load the content of the sqlite_stat1 and sqlite_stat3 tables. The ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] -** arrays. The contents of sqlite_stat2 are used to populate the +** arrays. The contents of sqlite_stat3 are used to populate the ** Index.aSample[] arrays. ** ** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR -** is returned. In this case, even if SQLITE_ENABLE_STAT2 was defined -** during compilation and the sqlite_stat2 table is present, no data is +** is returned. In this case, even if SQLITE_ENABLE_STAT3 was defined +** during compilation and the sqlite_stat3 table is present, no data is ** read from it. ** -** If SQLITE_ENABLE_STAT2 was defined during compilation and the -** sqlite_stat2 table is not present in the database, SQLITE_ERROR is +** If SQLITE_ENABLE_STAT3 was defined during compilation and the +** sqlite_stat3 table is not present in the database, SQLITE_ERROR is ** returned. However, in this case, data is read from the sqlite_stat1 ** table (if it is present) before returning. ** @@ -612,8 +1079,10 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3DefaultRowEst(pIdx); +#ifdef SQLITE_ENABLE_STAT3 sqlite3DeleteIndexSamples(db, pIdx); pIdx->aSample = 0; +#endif } /* Check to make sure the sqlite_stat1 table exists */ @@ -625,7 +1094,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Load new statistics out of the sqlite_stat1 table */ zSql = sqlite3MPrintf(db, - "SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase); + "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ @@ -634,78 +1103,10 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ } - /* Load the statistics from the sqlite_stat2 table. */ -#ifdef SQLITE_ENABLE_STAT2 - if( rc==SQLITE_OK && !sqlite3FindTable(db, "sqlite_stat2", sInfo.zDatabase) ){ - rc = SQLITE_ERROR; - } + /* Load the statistics from the sqlite_stat3 table. */ +#ifdef SQLITE_ENABLE_STAT3 if( rc==SQLITE_OK ){ - sqlite3_stmt *pStmt = 0; - - zSql = sqlite3MPrintf(db, - "SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase); - if( !zSql ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); - sqlite3DbFree(db, zSql); - } - - if( rc==SQLITE_OK ){ - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - char *zIndex; /* Index name */ - Index *pIdx; /* Pointer to the index object */ - - zIndex = (char *)sqlite3_column_text(pStmt, 0); - pIdx = zIndex ? sqlite3FindIndex(db, zIndex, sInfo.zDatabase) : 0; - if( pIdx ){ - int iSample = sqlite3_column_int(pStmt, 1); - if( iSample=0 ){ - int eType = sqlite3_column_type(pStmt, 2); - - if( pIdx->aSample==0 ){ - static const int sz = sizeof(IndexSample)*SQLITE_INDEX_SAMPLES; - pIdx->aSample = (IndexSample *)sqlite3DbMallocRaw(0, sz); - if( pIdx->aSample==0 ){ - db->mallocFailed = 1; - break; - } - memset(pIdx->aSample, 0, sz); - } - - assert( pIdx->aSample ); - { - IndexSample *pSample = &pIdx->aSample[iSample]; - pSample->eType = (u8)eType; - if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - pSample->u.r = sqlite3_column_double(pStmt, 2); - }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ - const char *z = (const char *)( - (eType==SQLITE_BLOB) ? - sqlite3_column_blob(pStmt, 2): - sqlite3_column_text(pStmt, 2) - ); - int n = sqlite3_column_bytes(pStmt, 2); - if( n>24 ){ - n = 24; - } - pSample->nByte = (u8)n; - if( n < 1){ - pSample->u.z = 0; - }else{ - pSample->u.z = sqlite3DbStrNDup(0, z, n); - if( pSample->u.z==0 ){ - db->mallocFailed = 1; - break; - } - } - } - } - } - } - } - rc = sqlite3_finalize(pStmt); - } + rc = loadStat3(db, sInfo.zDatabase); } #endif diff --git a/src/backup.c b/src/backup.c index 4d7ae318..bdf96bd8 100644 --- a/src/backup.c +++ b/src/backup.c @@ -410,102 +410,106 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** the case where the source and destination databases have the ** same schema version. */ - if( rc==SQLITE_DONE - && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK - ){ - int nDestTruncate; - - if( p->pDestDb ){ - sqlite3ResetInternalSchema(p->pDestDb, -1); - } - - /* Set nDestTruncate to the final number of pages in the destination - ** database. The complication here is that the destination page - ** size may be different to the source page size. - ** - ** If the source page size is smaller than the destination page size, - ** round up. In this case the call to sqlite3OsTruncate() below will - ** fix the size of the file. However it is important to call - ** sqlite3PagerTruncateImage() here so that any pages in the - ** destination file that lie beyond the nDestTruncate page mark are - ** journalled by PagerCommitPhaseOne() before they are destroyed - ** by the file truncation. - */ - assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) ); - assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) ); - if( pgszSrcpDest->pBt) ){ - nDestTruncate--; + if( rc==SQLITE_DONE ){ + rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); + if( rc==SQLITE_OK ){ + if( p->pDestDb ){ + sqlite3ResetInternalSchema(p->pDestDb, -1); + } + if( destMode==PAGER_JOURNALMODE_WAL ){ + rc = sqlite3BtreeSetVersion(p->pDest, 2); } - }else{ - nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } - sqlite3PagerTruncateImage(pDestPager, nDestTruncate); - - if( pgszSrc= iSize || ( - nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) - && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest - )); - - /* This call ensures that all data required to recreate the original - ** database has been stored in the journal for pDestPager and the - ** journal synced to disk. So at this point we may safely modify - ** the database file in any way, knowing that if a power failure - ** occurs, the original database will be reconstructed from the - ** journal file. */ - rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); - - /* Write the extra pages and truncate the database file as required. */ - iEnd = MIN(PENDING_BYTE + pgszDest, iSize); - for( - iOff=PENDING_BYTE+pgszSrc; - rc==SQLITE_OK && iOffpSrc) ); + assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) ); + if( pgszSrcpDest->pBt) ){ + nDestTruncate--; } - sqlite3PagerUnref(pSrcPg); - } - if( rc==SQLITE_OK ){ - rc = backupTruncateFile(pFile, iSize); + }else{ + nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } + sqlite3PagerTruncateImage(pDestPager, nDestTruncate); - /* Sync the database file to disk. */ - if( rc==SQLITE_OK ){ - rc = sqlite3PagerSync(pDestPager); + if( pgszSrc= iSize || ( + nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) + && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest + )); + + /* This call ensures that all data required to recreate the original + ** database has been stored in the journal for pDestPager and the + ** journal synced to disk. So at this point we may safely modify + ** the database file in any way, knowing that if a power failure + ** occurs, the original database will be reconstructed from the + ** journal file. */ + rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); + + /* Write the extra pages and truncate the database file as required */ + iEnd = MIN(PENDING_BYTE + pgszDest, iSize); + for( + iOff=PENDING_BYTE+pgszSrc; + rc==SQLITE_OK && iOffpDest, 0)) + ){ + rc = SQLITE_DONE; } - }else{ - rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); - } - - /* Finish committing the transaction to the destination database. */ - if( SQLITE_OK==rc - && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) - ){ - rc = SQLITE_DONE; } } @@ -539,14 +543,14 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ */ int sqlite3_backup_finish(sqlite3_backup *p){ sqlite3_backup **pp; /* Ptr to head of pagers backup list */ - sqlite3_mutex *mutex; /* Mutex to protect source database */ + MUTEX_LOGIC( sqlite3_mutex *mutex; ) /* Mutex to protect source database */ int rc; /* Value to return */ /* Enter the mutexes */ if( p==0 ) return SQLITE_OK; sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); - mutex = p->pSrcDb->mutex; + MUTEX_LOGIC( mutex = p->pSrcDb->mutex; ) if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } @@ -665,10 +669,18 @@ void sqlite3BackupRestart(sqlite3_backup *pBackup){ */ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc; + sqlite3_file *pFd; /* File descriptor for database pTo */ sqlite3_backup b; sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); + assert( sqlite3BtreeIsInTrans(pTo) ); + pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); + if( pFd->pMethods ){ + i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); + sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte); + } + /* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set ** to 0. This is used by the implementations of sqlite3_backup_step() ** and sqlite3_backup_finish() to detect that they are being called @@ -692,8 +704,11 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ rc = sqlite3_backup_finish(&b); if( rc==SQLITE_OK ){ pTo->pBt->pageSizeFixed = 0; + }else{ + sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } + assert( sqlite3BtreeIsInTrans(pTo)==0 ); sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); return rc; diff --git a/src/btree.c b/src/btree.c index 3d7162db..d64e172f 100644 --- a/src/btree.c +++ b/src/btree.c @@ -656,18 +656,21 @@ static int btreeMoveto( int rc; /* Status code */ UnpackedRecord *pIdxKey; /* Unpacked index key */ char aSpace[150]; /* Temp space for pIdxKey - to avoid a malloc */ + char *pFree = 0; if( pKey ){ assert( nKey==(i64)(int)nKey ); - pIdxKey = sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, - aSpace, sizeof(aSpace)); + pIdxKey = sqlite3VdbeAllocUnpackedRecord( + pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree + ); if( pIdxKey==0 ) return SQLITE_NOMEM; + sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey); }else{ pIdxKey = 0; } rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); - if( pKey ){ - sqlite3VdbeDeleteUnpackedRecord(pIdxKey); + if( pFree ){ + sqlite3DbFree(pCur->pKeyInfo->db, pFree); } return rc; } @@ -1763,17 +1766,19 @@ int sqlite3BtreeOpen( if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){ int nFullPathname = pVfs->mxPathname+1; char *zFullPathname = sqlite3Malloc(nFullPathname); - sqlite3_mutex *mutexShared; + MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) p->sharable = 1; if( !zFullPathname ){ sqlite3_free(p); return SQLITE_NOMEM; } sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); +#if SQLITE_THREADSAFE mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); sqlite3_mutex_enter(mutexOpen); mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex_enter(mutexShared); +#endif for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){ assert( pBt->nRef>0 ); if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) @@ -1879,9 +1884,9 @@ int sqlite3BtreeOpen( /* Add the new BtShared object to the linked list sharable BtShareds. */ if( p->sharable ){ - sqlite3_mutex *mutexShared; + MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) pBt->nRef = 1; - mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ @@ -1963,12 +1968,12 @@ btree_open_out: */ static int removeFromSharingList(BtShared *pBt){ #ifndef SQLITE_OMIT_SHARED_CACHE - sqlite3_mutex *pMaster; + MUTEX_LOGIC( sqlite3_mutex *pMaster; ) BtShared *pList; int removed = 0; assert( sqlite3_mutex_notheld(pBt->mutex) ); - pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(pMaster); pBt->nRef--; if( pBt->nRef<=0 ){ @@ -2743,11 +2748,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW1 ){ CellInfo info; btreeParseCellPtr(pPage, pCell, &info); - if( info.iOverflow ){ - if( iFrom==get4byte(&pCell[info.iOverflow]) ){ - put4byte(&pCell[info.iOverflow], iTo); - break; - } + if( info.iOverflow + && pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage + && iFrom==get4byte(&pCell[info.iOverflow]) + ){ + put4byte(&pCell[info.iOverflow], iTo); + break; } }else{ if( get4byte(pCell)==iFrom ){ @@ -3468,7 +3474,8 @@ static int btreeCursor( return SQLITE_READONLY; } if( iTable==1 && btreePagecount(pBt)==0 ){ - return SQLITE_EMPTY; + assert( wrFlag==0 ); + iTable = 0; } /* Now that no other errors can occur, finish filling in the BtCursor @@ -3933,21 +3940,55 @@ static int accessPayload( /* Need to read this page properly. It contains some of the ** range of data that is being read (eOp==0) or written (eOp!=0). */ - DbPage *pDbPage; +#ifdef SQLITE_DIRECT_OVERFLOW_READ + sqlite3_file *fd; +#endif int a = amt; - rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage); - if( rc==SQLITE_OK ){ - aPayload = sqlite3PagerGetData(pDbPage); - nextPage = get4byte(aPayload); - if( a + offset > ovflSize ){ - a = ovflSize - offset; - } - rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); - sqlite3PagerUnref(pDbPage); - offset = 0; - amt -= a; - pBuf += a; + if( a + offset > ovflSize ){ + a = ovflSize - offset; } + +#ifdef SQLITE_DIRECT_OVERFLOW_READ + /* If all the following are true: + ** + ** 1) this is a read operation, and + ** 2) data is required from the start of this overflow page, and + ** 3) the database is file-backed, and + ** 4) there is no open write-transaction, and + ** 5) the database is not a WAL database, + ** + ** then data can be read directly from the database file into the + ** output buffer, bypassing the page-cache altogether. This speeds + ** up loading large records that span many overflow pages. + */ + if( eOp==0 /* (1) */ + && offset==0 /* (2) */ + && pBt->inTransaction==TRANS_READ /* (4) */ + && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ + && pBt->pPage1->aData[19]==0x01 /* (5) */ + ){ + u8 aSave[4]; + u8 *aWrite = &pBuf[-4]; + memcpy(aSave, aWrite, 4); + rc = sqlite3OsRead(fd, aWrite, a+4, pBt->pageSize * (nextPage-1)); + nextPage = get4byte(aWrite); + memcpy(aWrite, aSave, 4); + }else +#endif + + { + DbPage *pDbPage; + rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage); + if( rc==SQLITE_OK ){ + aPayload = sqlite3PagerGetData(pDbPage); + nextPage = get4byte(aPayload); + rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); + sqlite3PagerUnref(pDbPage); + offset = 0; + } + } + amt -= a; + pBuf += a; } } } @@ -4222,6 +4263,9 @@ static int moveToRoot(BtCursor *pCur){ releasePage(pCur->apPage[i]); } pCur->iPage = 0; + }else if( pCur->pgnoRoot==0 ){ + pCur->eState = CURSOR_INVALID; + return SQLITE_OK; }else{ rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]); if( rc!=SQLITE_OK ){ @@ -4331,7 +4375,7 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( pCur->eState==CURSOR_INVALID ){ - assert( pCur->apPage[pCur->iPage]->nCell==0 ); + assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); *pRes = 1; }else{ assert( pCur->apPage[pCur->iPage]->nCell>0 ); @@ -4370,7 +4414,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( CURSOR_INVALID==pCur->eState ){ - assert( pCur->apPage[pCur->iPage]->nCell==0 ); + assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); *pRes = 1; }else{ assert( pCur->eState==CURSOR_VALID ); @@ -4443,12 +4487,12 @@ int sqlite3BtreeMovetoUnpacked( if( rc ){ return rc; } - assert( pCur->apPage[pCur->iPage] ); - assert( pCur->apPage[pCur->iPage]->isInit ); - assert( pCur->apPage[pCur->iPage]->nCell>0 || pCur->eState==CURSOR_INVALID ); + assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] ); + assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit ); + assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 ); if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; - assert( pCur->apPage[pCur->iPage]->nCell==0 ); + assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); return SQLITE_OK; } assert( pCur->apPage[0]->intKey || pIdxKey ); @@ -4543,7 +4587,6 @@ int sqlite3BtreeMovetoUnpacked( if( c==0 ){ if( pPage->intKey && !pPage->leaf ){ lwr = idx; - upr = lwr - 1; break; }else{ *pRes = 0; @@ -4561,7 +4604,7 @@ int sqlite3BtreeMovetoUnpacked( } pCur->aiIdx[pCur->iPage] = (u16)(idx = (lwr+upr)/2); } - assert( lwr==upr+1 ); + assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ chldPg = 0; @@ -4826,6 +4869,8 @@ static int allocateBtreePage( pTrunk = 0; goto end_allocate_page; } + assert( pTrunk!=0 ); + assert( pTrunk->aData!=0 ); k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */ if( k==0 && !searchList ){ @@ -5175,6 +5220,9 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){ if( info.iOverflow==0 ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } + if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){ + return SQLITE_CORRUPT; /* Cell extends past end of page */ + } ovflPgno = get4byte(&pCell[info.iOverflow]); assert( pBt->usableSize > 4 ); ovflPageSize = pBt->usableSize - 4; @@ -5950,13 +5998,15 @@ static int balance_nonroot( ** four bytes of the divider cell. So the pointer is safe to use ** later on. ** - ** Unless SQLite is compiled in secure-delete mode. In this case, + ** But not if we are in secure-delete mode. In secure-delete mode, ** the dropCell() routine will overwrite the entire cell with zeroes. ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ if( pBt->secureDelete ){ - int iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); + int iOff; + + iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); if( (iOff+szNew[i])>(int)pBt->usableSize ){ rc = SQLITE_CORRUPT_BKPT; memset(apOld, 0, (i+1)*sizeof(MemPage*)); @@ -6376,6 +6426,7 @@ static int balance_nonroot( /* Cell i is the cell immediately following the last cell on old ** sibling page j. If the siblings are not leaf pages of an ** intkey b-tree, then cell i was a divider cell. */ + assert( j+1 < ArraySize(apCopy) ); pOld = apCopy[++j]; iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow; if( pOld->nOverflow ){ @@ -7358,6 +7409,11 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ + + if( pCur->pgnoRoot==0 ){ + *pnEntry = 0; + return SQLITE_OK; + } rc = moveToRoot(pCur); /* Unless an error occurs, the following loop runs one iteration for each @@ -8142,7 +8198,6 @@ 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 diff --git a/src/build.c b/src/build.c index 97758cbc..e23aab6b 100644 --- a/src/build.c +++ b/src/build.c @@ -1674,7 +1674,7 @@ void sqlite3CreateView( const char *z; Token sEnd; DbFixer sFix; - Token *pName; + Token *pName = 0; int iDb; sqlite3 *db = pParse->db; @@ -1980,6 +1980,100 @@ static void destroyTable(Parse *pParse, Table *pTab){ #endif } +/* +** Remove entries from the sqlite_statN tables (for N in (1,2,3)) +** after a DROP INDEX or DROP TABLE command. +*/ +static void sqlite3ClearStatTables( + Parse *pParse, /* The parsing context */ + int iDb, /* The database number */ + const char *zType, /* "idx" or "tbl" */ + const char *zName /* Name of index or table */ +){ + int i; + const char *zDbName = pParse->db->aDb[iDb].zName; + for(i=1; i<=3; i++){ + char zTab[24]; + sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i); + if( sqlite3FindTable(pParse->db, zTab, zDbName) ){ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.%s WHERE %s=%Q", + zDbName, zTab, zType, zName + ); + } + } +} + +/* +** Generate code to drop a table. +*/ +void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){ + Vdbe *v; + sqlite3 *db = pParse->db; + Trigger *pTrigger; + Db *pDb = &db->aDb[iDb]; + + v = sqlite3GetVdbe(pParse); + assert( v!=0 ); + sqlite3BeginWriteOperation(pParse, 1, iDb); + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp0(v, OP_VBegin); + } +#endif + + /* Drop all triggers associated with the table being dropped. Code + ** is generated to remove entries from sqlite_master and/or + ** sqlite_temp_master if required. + */ + pTrigger = sqlite3TriggerList(pParse, pTab); + while( pTrigger ){ + assert( pTrigger->pSchema==pTab->pSchema || + pTrigger->pSchema==db->aDb[1].pSchema ); + sqlite3DropTriggerPtr(pParse, pTrigger); + pTrigger = pTrigger->pNext; + } + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* Remove any entries of the sqlite_sequence table associated with + ** the table being dropped. This is done before the table is dropped + ** at the btree level, in case the sqlite_sequence table needs to + ** move as a result of the drop (can happen in auto-vacuum mode). + */ + if( pTab->tabFlags & TF_Autoincrement ){ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", + pDb->zName, pTab->zName + ); + } +#endif + + /* Drop all SQLITE_MASTER table and index entries that refer to the + ** table. The program name loops through the master table and deletes + ** every row that refers to a table of the same name as the one being + ** dropped. Triggers are handled seperately because a trigger can be + ** created in the temp database that refers to a table in another + ** database. + */ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", + pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); + if( !isView && !IsVirtual(pTab) ){ + destroyTable(pParse, pTab); + } + + /* Remove the table entry from SQLite's internal schema and modify + ** the schema cookie. + */ + if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); + } + sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); + sqlite3ChangeCookie(pParse, iDb); + sqliteViewResetAll(db, iDb); +} + /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. @@ -2048,7 +2142,8 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ } } #endif - if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 + && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; } @@ -2072,75 +2167,11 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ */ v = sqlite3GetVdbe(pParse); if( v ){ - Trigger *pTrigger; - Db *pDb = &db->aDb[iDb]; sqlite3BeginWriteOperation(pParse, 1, iDb); - -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pTab) ){ - sqlite3VdbeAddOp0(v, OP_VBegin); - } -#endif + sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); sqlite3FkDropTable(pParse, pName, pTab); - - /* Drop all triggers associated with the table being dropped. Code - ** is generated to remove entries from sqlite_master and/or - ** sqlite_temp_master if required. - */ - pTrigger = sqlite3TriggerList(pParse, pTab); - while( pTrigger ){ - assert( pTrigger->pSchema==pTab->pSchema || - pTrigger->pSchema==db->aDb[1].pSchema ); - sqlite3DropTriggerPtr(pParse, pTrigger); - pTrigger = pTrigger->pNext; - } - -#ifndef SQLITE_OMIT_AUTOINCREMENT - /* Remove any entries of the sqlite_sequence table associated with - ** the table being dropped. This is done before the table is dropped - ** at the btree level, in case the sqlite_sequence table needs to - ** move as a result of the drop (can happen in auto-vacuum mode). - */ - if( pTab->tabFlags & TF_Autoincrement ){ - sqlite3NestedParse(pParse, - "DELETE FROM %s.sqlite_sequence WHERE name=%Q", - pDb->zName, pTab->zName - ); - } -#endif - - /* Drop all SQLITE_MASTER table and index entries that refer to the - ** table. The program name loops through the master table and deletes - ** every row that refers to a table of the same name as the one being - ** dropped. Triggers are handled seperately because a trigger can be - ** created in the temp database that refers to a table in another - ** database. - */ - sqlite3NestedParse(pParse, - "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", - pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); - - /* Drop any statistics from the sqlite_stat1 table, if it exists */ - if( sqlite3FindTable(db, "sqlite_stat1", db->aDb[iDb].zName) ){ - sqlite3NestedParse(pParse, - "DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q", pDb->zName, pTab->zName - ); - } - - if( !isView && !IsVirtual(pTab) ){ - destroyTable(pParse, pTab); - } - - /* Remove the table entry from SQLite's internal schema and modify - ** the schema cookie. - */ - if( IsVirtual(pTab) ){ - sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); - } - sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); - sqlite3ChangeCookie(pParse, iDb); + sqlite3CodeDropTable(pParse, pTab, iDb, isView); } - sqliteViewResetAll(db, iDb); exit_drop_table: sqlite3SrcListDelete(db, pName); @@ -2308,11 +2339,15 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ Table *pTab = pIndex->pTable; /* The table that is indexed */ int iTab = pParse->nTab++; /* Btree cursor used for pTab */ int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */ + int iSorter; /* Cursor opened by OpenSorter (if in use) */ int addr1; /* Address of top of loop */ + int addr2; /* Address to jump to for next iteration */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ +#ifdef SQLITE_OMIT_MERGE_SORT int regIdxKey; /* Registers containing the index key */ +#endif int regRecord; /* Register holding assemblied index record */ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); @@ -2341,10 +2376,44 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ if( memRootPage>=0 ){ sqlite3VdbeChangeP5(v, 1); } + +#ifndef SQLITE_OMIT_MERGE_SORT + /* Open the sorter cursor if we are to use one. */ + iSorter = pParse->nTab++; + sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)pKey, P4_KEYINFO); +#else + iSorter = iTab; +#endif + + /* Open the table. Loop through all rows of the table, inserting index + ** records into the sorter. */ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); regRecord = sqlite3GetTempReg(pParse); + +#ifndef SQLITE_OMIT_MERGE_SORT + sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1); + sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); + sqlite3VdbeJumpHere(v, addr1); + addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); + if( pIndex->onError!=OE_None ){ + int j2 = sqlite3VdbeCurrentAddr(v) + 3; + sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); + addr2 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord); + sqlite3HaltConstraint( + pParse, OE_Abort, "indexed columns are not unique", P4_STATIC + ); + }else{ + addr2 = sqlite3VdbeCurrentAddr(v); + } + sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); + sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); +#else regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1); + addr2 = addr1 + 1; if( pIndex->onError!=OE_None ){ const int regRowid = regIdxKey + pIndex->nColumn; const int j2 = sqlite3VdbeCurrentAddr(v) + 2; @@ -2363,13 +2432,16 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3HaltConstraint( pParse, OE_Abort, "indexed columns are not unique", P4_STATIC); } - sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); + sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); +#endif sqlite3ReleaseTempReg(pParse, regRecord); - sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); + sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp1(v, OP_Close, iTab); sqlite3VdbeAddOp1(v, OP_Close, iIdx); + sqlite3VdbeAddOp1(v, OP_Close, iSorter); } /* @@ -2439,6 +2511,7 @@ Index *sqlite3CreateIndex( assert( pName1 && pName2 ); iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ) goto exit_create_index; + assert( pName && pName->z ); #ifndef SQLITE_OMIT_TEMPDB /* If the index name was unqualified, check if the the table @@ -2466,6 +2539,7 @@ Index *sqlite3CreateIndex( assert( db->aDb[iDb].pSchema==pTab->pSchema ); }else{ assert( pName==0 ); + assert( pStart==0 ); pTab = pParse->pNewTable; if( !pTab ) goto exit_create_index; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -2508,6 +2582,7 @@ Index *sqlite3CreateIndex( if( pName ){ zName = sqlite3NameFromToken(db, pName); if( zName==0 ) goto exit_create_index; + assert( pName->z!=0 ); if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } @@ -2587,8 +2662,8 @@ Index *sqlite3CreateIndex( nCol = pList->nExpr; pIndex = sqlite3DbMallocZero(db, sizeof(Index) + /* Index structure */ + sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */ sizeof(int)*nCol + /* Index.aiColumn */ - sizeof(int)*(nCol+1) + /* Index.aiRowEst */ sizeof(char *)*nCol + /* Index.azColl */ sizeof(u8)*nCol + /* Index.aSortOrder */ nName + 1 + /* Index.zName */ @@ -2597,10 +2672,10 @@ Index *sqlite3CreateIndex( if( db->mallocFailed ){ goto exit_create_index; } - pIndex->azColl = (char**)(&pIndex[1]); + pIndex->aiRowEst = (tRowcnt*)(&pIndex[1]); + pIndex->azColl = (char**)(&pIndex->aiRowEst[nCol+1]); pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]); - pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]); - pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]); + pIndex->aSortOrder = (u8 *)(&pIndex->aiColumn[nCol]); pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]); zExtra = (char *)(&pIndex->zName[nName+1]); memcpy(pIndex->zName, zName, nName+1); @@ -2791,7 +2866,7 @@ Index *sqlite3CreateIndex( /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", onError==OE_None ? "" : " UNIQUE", - pEnd->z - pName->z + 1, + (int)(pEnd->z - pName->z) + 1, pName->z); }else{ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ @@ -2877,9 +2952,9 @@ exit_create_index: ** are based on typical values found in actual indices. */ void sqlite3DefaultRowEst(Index *pIdx){ - unsigned *a = pIdx->aiRowEst; + tRowcnt *a = pIdx->aiRowEst; int i; - unsigned n; + tRowcnt n; assert( a!=0 ); a[0] = pIdx->pTable->nRowEst; if( a[0]<10 ) a[0] = 10; @@ -2949,15 +3024,9 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), - pIndex->zName + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName ); - if( sqlite3FindTable(db, "sqlite_stat1", db->aDb[iDb].zName) ){ - sqlite3NestedParse(pParse, - "DELETE FROM %Q.sqlite_stat1 WHERE idx=%Q", - db->aDb[iDb].zName, pIndex->zName - ); - } + sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); sqlite3ChangeCookie(pParse, iDb); destroyRootPage(pParse, pIndex->tnum, iDb); sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0); @@ -3329,8 +3398,9 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ ** operator with A. This routine shifts that operator over to B. */ void sqlite3SrcListShiftJoinType(SrcList *p){ - if( p && p->a ){ + if( p ){ int i; + assert( p->a || p->nSrc==0 ); for(i=p->nSrc-1; i>0; i--){ p->a[i].jointype = p->a[i-1].jointype; } @@ -3368,13 +3438,10 @@ void sqlite3BeginTransaction(Parse *pParse, int type){ ** Commit a transaction */ void sqlite3CommitTransaction(Parse *pParse){ - sqlite3 *db; Vdbe *v; assert( pParse!=0 ); - db = pParse->db; - assert( db!=0 ); -/* if( db->aDb[0].pBt==0 ) return; */ + assert( pParse->db!=0 ); if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){ return; } @@ -3388,13 +3455,10 @@ void sqlite3CommitTransaction(Parse *pParse){ ** Rollback a transaction */ void sqlite3RollbackTransaction(Parse *pParse){ - sqlite3 *db; Vdbe *v; assert( pParse!=0 ); - db = pParse->db; - assert( db!=0 ); -/* if( db->aDb[0].pBt==0 ) return; */ + assert( pParse->db!=0 ); if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){ return; } diff --git a/src/ctime.c b/src/ctime.c index a128f61a..1688069c 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -114,8 +114,8 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif -#ifdef SQLITE_ENABLE_STAT2 - "ENABLE_STAT2", +#ifdef SQLITE_ENABLE_STAT3 + "ENABLE_STAT3", #endif #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", @@ -144,6 +144,9 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif +#ifdef SQLITE_MAX_SCHEMA_RETRY + "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), +#endif #ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif @@ -257,6 +260,9 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif +#ifdef SQLITE_OMIT_MERGE_SORT + "OMIT_MERGE_SORT", +#endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif diff --git a/src/date.c b/src/date.c index c0744e8c..758dd7c8 100644 --- a/src/date.c +++ b/src/date.c @@ -289,12 +289,18 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){ } /* -** Set the time to the current time reported by the VFS +** Set the time to the current time reported by the VFS. +** +** Return the number of errors. */ -static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ +static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ sqlite3 *db = sqlite3_context_db_handle(context); - sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD); - p->validJD = 1; + if( sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD)==SQLITE_OK ){ + p->validJD = 1; + return 0; + }else{ + return 1; + } } /* @@ -324,8 +330,7 @@ static int parseDateOrTime( }else if( parseHhMmSs(zDate, p)==0 ){ return 0; }else if( sqlite3StrICmp(zDate,"now")==0){ - setDateTimeToCurrent(context, p); - return 0; + return setDateTimeToCurrent(context, p); }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); p->validJD = 1; @@ -427,7 +432,9 @@ static int osLocaltime(time_t *t, struct tm *pTm){ #if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \ && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S) struct tm *pX; +#if SQLITE_THREADSAFE>0 sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif sqlite3_mutex_enter(mutex); pX = localtime(t); #ifndef SQLITE_OMIT_BUILTIN_TEST @@ -750,8 +757,9 @@ static int isDate( int eType; memset(p, 0, sizeof(*p)); if( argc==0 ){ - setDateTimeToCurrent(context, p); - }else if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT + return setDateTimeToCurrent(context, p); + } + if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT || eType==SQLITE_INTEGER ){ p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5); p->validJD = 1; @@ -1063,31 +1071,28 @@ static void currentTimeFunc( char *zFormat = (char *)sqlite3_user_data(context); sqlite3 *db; sqlite3_int64 iT; + struct tm *pTm; + struct tm sNow; char zBuf[20]; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); db = sqlite3_context_db_handle(context); - sqlite3OsCurrentTimeInt64(db->pVfs, &iT); + if( sqlite3OsCurrentTimeInt64(db->pVfs, &iT) ) return; t = iT/1000 - 10000*(sqlite3_int64)21086676; #ifdef HAVE_GMTIME_R - { - struct tm sNow; - gmtime_r(&t, &sNow); - strftime(zBuf, 20, zFormat, &sNow); - } + pTm = gmtime_r(&t, &sNow); #else - { - struct tm *pTm; - sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); - pTm = gmtime(&t); - strftime(zBuf, 20, zFormat, pTm); - sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); - } + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); + pTm = gmtime(&t); + if( pTm ) memcpy(&sNow, pTm, sizeof(sNow)); + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); #endif - - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + if( pTm ){ + strftime(zBuf, 20, zFormat, &sNow); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + } } #endif diff --git a/src/delete.c b/src/delete.c index ec0ecec7..147a5ca8 100644 --- a/src/delete.c +++ b/src/delete.c @@ -371,7 +371,9 @@ void sqlite3DeleteFrom( /* Collect rowids of every row to be deleted. */ sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK); + pWInfo = sqlite3WhereBegin( + pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK + ); if( pWInfo==0 ) goto delete_from_cleanup; regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid); sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid); diff --git a/src/expr.c b/src/expr.c index be2f4d7c..d5061737 100644 --- a/src/expr.c +++ b/src/expr.c @@ -403,7 +403,8 @@ Expr *sqlite3ExprAlloc( }else{ int c; pNew->u.zToken = (char*)&pNew[1]; - memcpy(pNew->u.zToken, pToken->z, pToken->n); + assert( pToken->z!=0 || pToken->n==0 ); + if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); pNew->u.zToken[pToken->n] = 0; if( dequote && nExtra>=3 && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){ @@ -901,7 +902,9 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; - pNewItem->isPopulated = pOldItem->isPopulated; + pNewItem->addrFillSub = pOldItem->addrFillSub; + pNewItem->regReturn = pOldItem->regReturn; + pNewItem->isCorrelated = pOldItem->isCorrelated; pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); pNewItem->notIndexed = pOldItem->notIndexed; pNewItem->pIndex = pOldItem->pIndex; @@ -1440,11 +1443,19 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0); if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){ sqlite3 *db = pParse->db; /* Database connection */ - Expr *pExpr = p->pEList->a[0].pExpr; /* Expression */ - int iCol = pExpr->iColumn; /* Index of column */ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ - Table *pTab = p->pSrc->a[0].pTab; /* Table . */ + Table *pTab; /* Table
. */ + Expr *pExpr; /* Expression */ + int iCol; /* Index of column */ int iDb; /* Database idx for pTab */ + + assert( p ); /* Because of isCandidateForInOpt(p) */ + assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ + assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ + assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ + pTab = p->pSrc->a[0].pTab; + pExpr = p->pEList->a[0].pExpr; + iCol = pExpr->iColumn; /* Code an OP_VerifyCookie and OP_TableLock for
. */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -1460,8 +1471,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ int iMem = ++pParse->nMem; int iAddr; - iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); - sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); + iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; @@ -1492,8 +1502,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ char *pKey; pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); - iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); - sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); + iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); @@ -1574,7 +1583,7 @@ int sqlite3CodeSubselect( int rMayHaveNull, /* Register that records whether NULLs exist in RHS */ int isRowid /* If true, LHS of IN operator is a rowid */ ){ - int testAddr = 0; /* One-time test address */ + int testAddr = -1; /* One-time test address */ int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; @@ -1592,15 +1601,13 @@ int sqlite3CodeSubselect( */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){ int mem = ++pParse->nMem; - sqlite3VdbeAddOp1(v, OP_If, mem); - testAddr = sqlite3VdbeAddOp2(v, OP_Integer, 1, mem); - assert( testAddr>0 || pParse->db->mallocFailed ); + testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem); } #ifndef SQLITE_OMIT_EXPLAIN if( pParse->explain==2 ){ char *zMsg = sqlite3MPrintf( - pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr?"":"CORRELATED ", + pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ", pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId ); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); @@ -1692,9 +1699,9 @@ int sqlite3CodeSubselect( ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ - if( testAddr && !sqlite3ExprIsConstant(pE2) ){ - sqlite3VdbeChangeToNoop(v, testAddr-1, 2); - testAddr = 0; + if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){ + sqlite3VdbeChangeToNoop(v, testAddr); + testAddr = -1; } /* Evaluate the expression and insert it into the temp table */ @@ -1763,8 +1770,8 @@ int sqlite3CodeSubselect( } } - if( testAddr ){ - sqlite3VdbeJumpHere(v, testAddr-1); + if( testAddr>=0 ){ + sqlite3VdbeJumpHere(v, testAddr); } sqlite3ExprCachePop(pParse, 1); @@ -2286,7 +2293,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ inReg = pCol->iMem; break; }else if( pAggInfo->useSortingIdx ){ - sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdx, + sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); break; } @@ -3455,7 +3462,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){ } }else if( pA->op!=TK_COLUMN && pA->u.zToken ){ if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2; - if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ){ + if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } diff --git a/src/fkey.c b/src/fkey.c index dda8a50d..82e4cdc4 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -560,7 +560,7 @@ static void fkScanChildren( ** clause. If the constraint is not deferred, throw an exception for ** each row found. Otherwise, for deferred constraints, increment the ** deferred constraint counter by nIncr for each row selected. */ - pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0); if( nIncr>0 && pFKey->isDeferred==0 ){ sqlite3ParseToplevel(pParse)->mayAbort = 1; } @@ -734,7 +734,24 @@ void sqlite3FkCheck( pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); } if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ + assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); if( !isIgnoreErrors || db->mallocFailed ) return; + if( pTo==0 ){ + /* If isIgnoreErrors is true, then a table is being dropped. In this + ** case SQLite runs a "DELETE FROM xxx" on the table being dropped + ** before actually dropping it in order to check FK constraints. + ** If the parent table of an FK constraint on the current table is + ** missing, behave as if it is empty. i.e. decrement the relevant + ** FK counter for each row of the current table with non-NULL keys. + */ + Vdbe *v = sqlite3GetVdbe(pParse); + int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; + for(i=0; inCol; i++){ + int iReg = pFKey->aCol[i].iFrom + regOld + 1; + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); + } + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); + } continue; } assert( pFKey->nCol==1 || (aiFree && pIdx) ); @@ -1107,6 +1124,7 @@ static Trigger *fkActionTrigger( fkTriggerDelete(db, pTrigger); return 0; } + assert( pStep!=0 ); switch( action ){ case OE_Restrict: diff --git a/src/func.c b/src/func.c index 75046704..0514b384 100644 --- a/src/func.c +++ b/src/func.c @@ -332,16 +332,15 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ if( z2 ){ z1 = contextMalloc(context, ((i64)n)+1); if( z1 ){ - memcpy(z1, z2, n+1); - for(i=0; z1[i]; i++){ - z1[i] = (char)sqlite3Toupper(z1[i]); + for(i=0; idb->flags & SQLITE_CountRows)!=0 ){ + return 0; + } /* If we get this far, it means either: ** diff --git a/src/lempar.c b/src/lempar.c index fb52490e..cb6025e8 100644 --- a/src/lempar.c +++ b/src/lempar.c @@ -716,7 +716,9 @@ void Parse( ){ YYMINORTYPE yyminorunion; int yyact; /* The parser action. */ +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) int yyendofinput; /* True if we are at the end of input */ +#endif #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif @@ -739,7 +741,9 @@ void Parse( yypParser->yystack[0].major = 0; } yyminorunion.yy0 = yyminor; +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); +#endif ParseARG_STORE; #ifndef NDEBUG @@ -751,7 +755,6 @@ void Parse( do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyactyyerrcnt--; yymajor = YYNOCODE; diff --git a/src/loadext.c b/src/loadext.c index c832e684..e9c97adf 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -84,6 +84,8 @@ # define sqlite3_create_module 0 # define sqlite3_create_module_v2 0 # define sqlite3_declare_vtab 0 +# define sqlite3_vtab_config 0 +# define sqlite3_vtab_on_conflict 0 #endif #ifdef SQLITE_OMIT_SHARED_CACHE @@ -107,6 +109,7 @@ #define sqlite3_blob_open 0 #define sqlite3_blob_read 0 #define sqlite3_blob_write 0 +#define sqlite3_blob_reopen 0 #endif /* @@ -372,6 +375,9 @@ static const sqlite3_api_routines sqlite3Apis = { 0, 0, #endif + sqlite3_blob_reopen, + sqlite3_vtab_config, + sqlite3_vtab_on_conflict, }; /* @@ -397,7 +403,7 @@ static int sqlite3LoadExtension( int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); char *zErrmsg = 0; void **aHandle; - const int nMsg = 300; + int nMsg = 300 + sqlite3Strlen30(zFile); if( pzErrMsg ) *pzErrMsg = 0; @@ -434,6 +440,7 @@ static int sqlite3LoadExtension( sqlite3OsDlSym(pVfs, handle, zProc); if( xInit==0 ){ if( pzErrMsg ){ + nMsg += sqlite3Strlen30(zProc); *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, diff --git a/src/main.c b/src/main.c index b2366304..42bbba5d 100644 --- a/src/main.c +++ b/src/main.c @@ -106,7 +106,7 @@ char *sqlite3_temp_directory = 0; ** without blocking. */ int sqlite3_initialize(void){ - sqlite3_mutex *pMaster; /* The main static mutex */ + MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ int rc; /* Result code */ #ifdef SQLITE_OMIT_WSD @@ -140,7 +140,7 @@ int sqlite3_initialize(void){ ** malloc subsystem - this implies that the allocation of a static ** mutex must not require support from the malloc subsystem. */ - pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(pMaster); sqlite3GlobalConfig.isMutexInit = 1; if( !sqlite3GlobalConfig.isMallocInit ){ @@ -234,6 +234,16 @@ int sqlite3_initialize(void){ #endif #endif + /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT + ** compile-time option. + */ +#ifdef SQLITE_EXTRA_INIT + if( rc==SQLITE_OK && sqlite3GlobalConfig.isInit ){ + int SQLITE_EXTRA_INIT(void); + rc = SQLITE_EXTRA_INIT(); + } +#endif + return rc; } @@ -1204,13 +1214,13 @@ int sqlite3_overload_function( int nArg ){ int nName = sqlite3Strlen30(zName); - int rc; + int rc = SQLITE_OK; sqlite3_mutex_enter(db->mutex); if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){ - sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, - 0, sqlite3InvalidFunction, 0, 0, 0); + rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, + 0, sqlite3InvalidFunction, 0, 0, 0); } - rc = sqlite3ApiExit(db, SQLITE_OK); + rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } @@ -2272,6 +2282,7 @@ opendb_out: sqlite3_mutex_leave(db->mutex); } rc = sqlite3_errcode(db); + assert( db!=0 || rc==SQLITE_NOMEM ); if( rc==SQLITE_NOMEM ){ sqlite3_close(db); db = 0; diff --git a/src/mem3.c b/src/mem3.c index e2d66815..1a1b791f 100644 --- a/src/mem3.c +++ b/src/mem3.c @@ -433,7 +433,7 @@ static void *memsys3MallocUnsafe(int nByte){ ** This function assumes that the necessary mutexes, if any, are ** already held by the caller. Hence "Unsafe". */ -void memsys3FreeUnsafe(void *pOld){ +static void memsys3FreeUnsafe(void *pOld){ Mem3Block *p = (Mem3Block*)pOld; int i; u32 size, x; @@ -508,7 +508,7 @@ static void *memsys3Malloc(int nBytes){ /* ** Free memory. */ -void memsys3Free(void *pPrior){ +static void memsys3Free(void *pPrior){ assert( pPrior ); memsys3Enter(); memsys3FreeUnsafe(pPrior); @@ -518,7 +518,7 @@ void memsys3Free(void *pPrior){ /* ** Change the size of an existing memory allocation */ -void *memsys3Realloc(void *pPrior, int nBytes){ +static void *memsys3Realloc(void *pPrior, int nBytes){ int nOld; void *p; if( pPrior==0 ){ diff --git a/src/mutex.h b/src/mutex.h index c24f3da4..b0e552c7 100644 --- a/src/mutex.h +++ b/src/mutex.h @@ -60,12 +60,15 @@ */ #define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) #define sqlite3_mutex_free(X) -#define sqlite3_mutex_enter(X) +#define sqlite3_mutex_enter(X) #define sqlite3_mutex_try(X) SQLITE_OK -#define sqlite3_mutex_leave(X) +#define sqlite3_mutex_leave(X) #define sqlite3_mutex_held(X) ((void)(X),1) #define sqlite3_mutex_notheld(X) ((void)(X),1) #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() +#define MUTEX_LOGIC(X) +#else +#define MUTEX_LOGIC(X) X #endif /* defined(SQLITE_MUTEX_OMIT) */ diff --git a/src/os.c b/src/os.c index ba0438ad..0b13c86e 100644 --- a/src/os.c +++ b/src/os.c @@ -136,7 +136,7 @@ int sqlite3OsOpen( ** 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 & 0x87f3f, pFlagsOut); + rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut); assert( rc==SQLITE_OK || pFile->pMethods==0 ); return rc; } @@ -208,7 +208,7 @@ int sqlite3OsOpenMalloc( ){ int rc = SQLITE_NOMEM; sqlite3_file *pFile; - pFile = (sqlite3_file *)sqlite3Malloc(pVfs->szOsFile); + pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); if( pFile ){ rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); if( rc!=SQLITE_OK ){ @@ -297,12 +297,12 @@ static void vfsUnlink(sqlite3_vfs *pVfs){ ** true. */ int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ - sqlite3_mutex *mutex = 0; + MUTEX_LOGIC(sqlite3_mutex *mutex;) #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return rc; #endif - mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); if( makeDflt || vfsList==0 ){ diff --git a/src/os_common.h b/src/os_common.h index eba856be..f6c3e7ff 100644 --- a/src/os_common.h +++ b/src/os_common.h @@ -29,11 +29,14 @@ # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif -#ifdef SQLITE_DEBUG -int sqlite3OSTrace = 0; -#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) +# ifndef SQLITE_DEBUG_OS_TRACE +# define SQLITE_DEBUG_OS_TRACE 0 +# endif + int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; +# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X #else -#define OSTRACE(X) +# define OSTRACE(X) #endif /* diff --git a/src/os_unix.c b/src/os_unix.c index 682e74c9..0ea6daf2 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -208,7 +208,6 @@ struct unixFile { sqlite3_io_methods const *pMethod; /* Always the first entry */ unixInodeInfo *pInode; /* Info about locks on this inode */ int h; /* The file descriptor */ - int dirfd; /* File descriptor for the directory */ unsigned char eFileLock; /* The type of lock held on this fd */ unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ @@ -250,8 +249,14 @@ struct unixFile { /* ** Allowed values for the unixFile.ctrlFlags bitmask: */ -#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ -#define UNIXFILE_RDONLY 0x02 /* Connection is read only */ +#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ +#define UNIXFILE_RDONLY 0x02 /* Connection is read only */ +#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ +#ifndef SQLITE_DISABLE_DIRSYNC +# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ +#else +# define UNIXFILE_DIRSYNC 0x00 +#endif /* ** Include code that is common to all os_*.c files @@ -297,6 +302,9 @@ static int posixOpen(const char *zFile, int flags, int mode){ return open(zFile, flags, mode); } +/* Forward reference */ +static int openDirectory(const char*, int*); + /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during @@ -393,6 +401,12 @@ static struct unix_syscall { #endif #define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent) + { "unlink", (sqlite3_syscall_ptr)unlink, 0 }, +#define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent) + + { "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 }, +#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent) + }; /* End of the overrideable system calls */ /* @@ -514,7 +528,7 @@ static int unixMutexHeld(void) { #endif -#ifdef SQLITE_DEBUG +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) /* ** Helper function for printing out trace information from debugging ** binaries. This returns the string represetation of the supplied @@ -677,7 +691,9 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { case ENODEV: case ENXIO: case ENOENT: +#ifdef ESTALE /* ESTALE is not defined on Interix systems */ case ESTALE: +#endif case ENOSYS: /* these should force the client to close the file and reconnect */ @@ -1347,14 +1363,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){ */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; - unixInodeInfo *pInode = pFile->pInode; + unixInodeInfo *pInode; struct flock lock; int tErrno = 0; assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), - azFileLock(pInode->eFileLock), pInode->nShared , getpid())); + azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid())); /* If there is already a lock of this type or more restrictive on the ** unixFile, do nothing. Don't use the end_lock: exit path, as @@ -1558,7 +1574,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ unixInodeInfo *pInode; struct flock lock; int rc = SQLITE_OK; - int h; assert( pFile ); OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, @@ -1570,14 +1585,10 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ return SQLITE_OK; } unixEnterMutex(); - h = pFile->h; pInode = pFile->pInode; assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); - SimulateIOErrorBenign(1); - SimulateIOError( h=(-1) ) - SimulateIOErrorBenign(0); #ifndef NDEBUG /* When reducing a lock such that other processes can start @@ -1588,11 +1599,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ ** the file has changed and hence might not know to flush their ** cache. The use of a stale cache can lead to database corruption. */ -#if 0 - assert( pFile->inNormalWrite==0 - || pFile->dbUpdate==0 - || pFile->transCntrChng==1 ); -#endif pFile->inNormalWrite = 0; #endif @@ -1694,9 +1700,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; - SimulateIOErrorBenign(1); - SimulateIOError( h=(-1) ) - SimulateIOErrorBenign(0); if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = NO_LOCK; }else{ @@ -1747,10 +1750,6 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){ */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; - if( pFile->dirfd>=0 ){ - robust_close(pFile, pFile->dirfd, __LINE__); - pFile->dirfd=-1; - } if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); pFile->h = -1; @@ -1758,7 +1757,7 @@ static int closeUnixFile(sqlite3_file *id){ #if OS_VXWORKS if( pFile->pId ){ if( pFile->isDelete ){ - unlink(pFile->pId->zCanonicalName); + osUnlink(pFile->pId->zCanonicalName); } vxworksReleaseFileId(pFile->pId); pFile->pId = 0; @@ -2007,7 +2006,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { /* To fully unlock the database, delete the lock file */ assert( eFileLock==NO_LOCK ); - if( unlink(zLockFile) ){ + if( osUnlink(zLockFile) ){ int rc = 0; int tErrno = errno; if( ENOENT != tErrno ){ @@ -2513,11 +2512,12 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; + afpLockingContext *context; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); - afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; + context = (afpLockingContext *) pFile->lockingContext; if( context->reserved ){ *pResOut = 1; return SQLITE_OK; @@ -2657,7 +2657,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ ** operating system calls for the specified lock. */ if( eFileLock==SHARED_LOCK ){ - int lrc1, lrc2, lrc1Errno; + int lrc1, lrc2, lrc1Errno = 0; long lk, mask; assert( pInode->nShared==0 ); @@ -3031,17 +3031,19 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ #elif defined(USE_PREAD64) do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR); #else - newOffset = lseek(id->h, offset, SEEK_SET); - SimulateIOError( newOffset-- ); - if( newOffset!=offset ){ - if( newOffset == -1 ){ - ((unixFile*)id)->lastErrno = errno; - }else{ - ((unixFile*)id)->lastErrno = 0; + do{ + newOffset = lseek(id->h, offset, SEEK_SET); + SimulateIOError( newOffset-- ); + if( newOffset!=offset ){ + if( newOffset == -1 ){ + ((unixFile*)id)->lastErrno = errno; + }else{ + ((unixFile*)id)->lastErrno = 0; + } + return -1; } - return -1; - } - do{ got = osWrite(id->h, pBuf, cnt); }while( got<0 && errno==EINTR ); + got = osWrite(id->h, pBuf, cnt); + }while( got<0 && errno==EINTR ); #endif TIMER_END; if( got<0 ){ @@ -3131,11 +3133,11 @@ int sqlite3_fullsync_count = 0; /* ** We do not trust systems to provide a working fdatasync(). Some do. -** Others do no. To be safe, we will stick with the (slower) fsync(). -** If you know that your system does support fdatasync() correctly, +** Others do no. To be safe, we will stick with the (slightly slower) +** fsync(). If you know that your system does support fdatasync() correctly, ** then simply compile with -Dfdatasync=fdatasync */ -#if !defined(fdatasync) && !defined(__linux__) +#if !defined(fdatasync) # define fdatasync fsync #endif @@ -3243,6 +3245,50 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ return rc; } +/* +** Open a file descriptor to the directory containing file zFilename. +** If successful, *pFd is set to the opened file descriptor and +** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM +** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined +** value. +** +** The directory file descriptor is used for only one thing - to +** fsync() a directory to make sure file creation and deletion events +** are flushed to disk. Such fsyncs are not needed on newer +** journaling filesystems, but are required on older filesystems. +** +** This routine can be overridden using the xSetSysCall interface. +** The ability to override this routine was added in support of the +** chromium sandbox. Opening a directory is a security risk (we are +** told) so making it overrideable allows the chromium sandbox to +** replace this routine with a harmless no-op. To make this routine +** a no-op, replace it with a stub that returns SQLITE_OK but leaves +** *pFd set to a negative number. +** +** If SQLITE_OK is returned, the caller is responsible for closing +** the file descriptor *pFd using close(). +*/ +static int openDirectory(const char *zFilename, int *pFd){ + int ii; + int fd = -1; + char zDirname[MAX_PATHNAME+1]; + + sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); + for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--); + if( ii>0 ){ + zDirname[ii] = '\0'; + fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); + if( fd>=0 ){ +#ifdef FD_CLOEXEC + osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); +#endif + OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); + } + } + *pFd = fd; + return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); +} + /* ** Make sure all writes to a particular file are committed to disk. ** @@ -3283,28 +3329,23 @@ static int unixSync(sqlite3_file *id, int flags){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); } - if( pFile->dirfd>=0 ){ - OSTRACE(("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, + + /* Also fsync the directory containing the file if the DIRSYNC flag + ** is set. This is a one-time occurrance. Many systems (examples: AIX) + ** are unable to fsync a directory, so ignore errors on the fsync. + */ + if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ + int dirfd; + OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, HAVE_FULLFSYNC, isFullsync)); -#ifndef SQLITE_DISABLE_DIRSYNC - /* The directory sync is only attempted if full_fsync is - ** turned off or unavailable. If a full_fsync occurred above, - ** then the directory sync is superfluous. - */ - if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){ - /* - ** We have received multiple reports of fsync() returning - ** errors when applied to directories on certain file systems. - ** A failed directory sync is not a big deal. So it seems - ** better to ignore the error. Ticket #1657 - */ - /* pFile->lastErrno = errno; */ - /* return SQLITE_IOERR; */ + rc = osOpenDirectory(pFile->zPath, &dirfd); + if( rc==SQLITE_OK && dirfd>=0 ){ + full_fsync(dirfd, 0, 0); + robust_close(pFile, dirfd, __LINE__); + }else if( rc==SQLITE_CANTOPEN ){ + rc = SQLITE_OK; } -#endif - /* Only need to sync once, so close the directory when we are done */ - robust_close(pFile, pFile->dirfd, __LINE__); - pFile->dirfd = -1; + pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; } return rc; } @@ -3386,14 +3427,12 @@ static int proxyFileControl(sqlite3_file*,int,void*); /* ** This function is called to handle the SQLITE_FCNTL_SIZE_HINT -** file-control operation. -** -** If the user has configured a chunk-size for this file, it could be -** that the file needs to be extended at this point. Otherwise, the -** SQLITE_FCNTL_SIZE_HINT operation is a no-op for Unix. +** file-control operation. Enlarge the database to nBytes in size +** (rounded up to the next chunk-size). If the database is already +** nBytes or larger, this routine is a no-op. */ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ - if( pFile->szChunk ){ + if( pFile->szChunk>0 ){ i64 nSize; /* Required file size */ struct stat buf; /* Used to hold return values of fstat() */ @@ -3442,21 +3481,37 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ + unixFile *pFile = (unixFile*)id; switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { - *(int*)pArg = ((unixFile*)id)->eFileLock; + *(int*)pArg = pFile->eFileLock; return SQLITE_OK; } case SQLITE_LAST_ERRNO: { - *(int*)pArg = ((unixFile*)id)->lastErrno; + *(int*)pArg = pFile->lastErrno; return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { - ((unixFile*)id)->szChunk = *(int *)pArg; + pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { - return fcntlSizeHint((unixFile *)id, *(i64 *)pArg); + int rc; + SimulateIOErrorBenign(1); + rc = fcntlSizeHint(pFile, *(i64 *)pArg); + SimulateIOErrorBenign(0); + return rc; + } + case SQLITE_FCNTL_PERSIST_WAL: { + int bPersist = *(int*)pArg; + if( bPersist<0 ){ + *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0; + }else if( bPersist==0 ){ + pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL; + }else{ + pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL; + } + return SQLITE_OK; } #ifndef NDEBUG /* The pager calls this method to signal that it has done @@ -3572,11 +3627,9 @@ struct unixShm { unixShmNode *pShmNode; /* The underlying unixShmNode object */ unixShm *pNext; /* Next unixShm with the same unixShmNode */ u8 hasMutex; /* True if holding the unixShmNode mutex */ + u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ -#ifdef SQLITE_DEBUG - u8 id; /* Id of this connection within its unixShmNode */ -#endif }; /* @@ -3672,7 +3725,7 @@ static void unixShmPurge(unixFile *pFd){ if( p && p->nRef==0 ){ int i; assert( p->pInode==pFd->pInode ); - if( p->mutex ) sqlite3_mutex_free(p->mutex); + sqlite3_mutex_free(p->mutex); for(i=0; inRegion; i++){ if( p->h>=0 ){ munmap(p->apRegion[i], p->szRegion); @@ -3788,16 +3841,15 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ } if( pInode->bProcessLock==0 ){ - pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT, - (sStat.st_mode & 0777)); + const char *zRO; + int openFlags = O_RDWR | O_CREAT; + zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm"); + if( zRO && sqlite3GetBoolean(zRO) ){ + openFlags = O_RDONLY; + pShmNode->isReadonly = 1; + } + pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777)); if( pShmNode->h<0 ){ - const char *zRO; - zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm"); - if( zRO && sqlite3GetBoolean(zRO) ){ - pShmNode->h = robust_open(zShmFilename, O_RDONLY, - (sStat.st_mode & 0777)); - pShmNode->isReadonly = 1; - } if( pShmNode->h<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename); goto shm_open_err; @@ -4141,7 +4193,7 @@ static int unixShmUnmap( assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ - if( deleteFlag && pShmNode->h>=0 ) unlink(pShmNode->zFilename); + if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename); unixShmPurge(pDbFd); } unixLeaveMutex(); @@ -4454,7 +4506,7 @@ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); static int fillInUnixFile( sqlite3_vfs *pVfs, /* Pointer to vfs object */ int h, /* Open file descriptor of file being opened */ - int dirfd, /* Directory file descriptor */ + int syncDir, /* True to sync directory on first sync */ sqlite3_file *pId, /* Write to the unixFile structure here */ const char *zFilename, /* Name of the file being opened */ int noLock, /* Omit locking if true */ @@ -4483,9 +4535,11 @@ static int fillInUnixFile( assert( zFilename==0 || zFilename[0]=='/' ); #endif + /* No locking occurs in temporary files */ + assert( zFilename!=0 || noLock ); + OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; - pNew->dirfd = dirfd; pNew->zPath = zFilename; if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ pNew->ctrlFlags = UNIXFILE_EXCL; @@ -4495,6 +4549,9 @@ static int fillInUnixFile( if( isReadOnly ){ pNew->ctrlFlags |= UNIXFILE_RDONLY; } + if( syncDir ){ + pNew->ctrlFlags |= UNIXFILE_DIRSYNC; + } #if OS_VXWORKS pNew->pId = vxworksFindFileId(zFilename); @@ -4582,6 +4639,7 @@ static int fillInUnixFile( */ char *zLockFile; int nFilename; + assert( zFilename!=0 ); nFilename = (int)strlen(zFilename) + 6; zLockFile = (char *)sqlite3_malloc(nFilename); if( zLockFile==0 ){ @@ -4621,13 +4679,12 @@ static int fillInUnixFile( if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); h = -1; - unlink(zFilename); + osUnlink(zFilename); isDelete = 0; } pNew->isDelete = isDelete; #endif if( rc!=SQLITE_OK ){ - if( dirfd>=0 ) robust_close(pNew, dirfd, __LINE__); if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ pNew->pMethod = pLockingStyle; @@ -4636,37 +4693,6 @@ static int fillInUnixFile( return rc; } -/* -** Open a file descriptor to the directory containing file zFilename. -** If successful, *pFd is set to the opened file descriptor and -** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM -** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined -** value. -** -** If SQLITE_OK is returned, the caller is responsible for closing -** the file descriptor *pFd using close(). -*/ -static int openDirectory(const char *zFilename, int *pFd){ - int ii; - int fd = -1; - char zDirname[MAX_PATHNAME+1]; - - sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); - for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--); - if( ii>0 ){ - zDirname[ii] = '\0'; - fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); - if( fd>=0 ){ -#ifdef FD_CLOEXEC - osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); -#endif - OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); - } - } - *pFd = fd; - return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); -} - /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. @@ -4781,7 +4807,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a resusable file descriptor are not dire. */ - if( 0==stat(zPath, &sStat) ){ + if( 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; unixEnterMutex(); @@ -4848,16 +4874,24 @@ static int findCreateFileMode( ** "-journalNN" ** "-walNN" ** - ** where NN is a 4 digit decimal number. The NN naming schemes are + ** where NN is a decimal number. The NN naming schemes are ** used by the test_multiplex.c module. */ nDb = sqlite3Strlen30(zPath) - 1; - while( nDb>0 && zPath[nDb]!='-' ) nDb--; - if( nDb==0 ) return SQLITE_OK; +#ifdef SQLITE_ENABLE_8_3_NAMES + while( nDb>0 && !sqlite3Isalnum(zPath[nDb]) ) nDb--; + if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK; +#else + while( zPath[nDb]!='-' ){ + assert( nDb>0 ); + assert( zPath[nDb]!='\n' ); + nDb--; + } +#endif memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; - if( 0==stat(zDb, &sStat) ){ + if( 0==osStat(zDb, &sStat) ){ *pMode = sStat.st_mode & 0777; }else{ rc = SQLITE_IOERR_FSTAT; @@ -4899,7 +4933,6 @@ static int unixOpen( ){ unixFile *p = (unixFile *)pFile; int fd = -1; /* File descriptor returned by open() */ - int dirfd = -1; /* Directory file descriptor */ int openFlags = 0; /* Flags to pass to open() */ int eType = flags&0xFFFFFF00; /* Type of file to open */ int noLock; /* True to omit locking primitives */ @@ -4913,12 +4946,15 @@ static int unixOpen( #if SQLITE_ENABLE_LOCKING_STYLE int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY); #endif +#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE + struct statfs fsInfo; +#endif /* If creating a master or main-file journal, this function will open ** a file-descriptor on the directory too. The first time unixSync() ** is called the directory file descriptor will be fsync()ed and close()d. */ - int isOpenDirectory = (isCreate && ( + int syncDir = (isCreate && ( eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL @@ -4972,7 +5008,7 @@ static int unixOpen( p->pUnused = pUnused; }else if( !zName ){ /* If zName is NULL, the upper layer is requesting a temp file. */ - assert(isDelete && !isOpenDirectory); + assert(isDelete && !syncDir); rc = unixGetTempname(MAX_PATHNAME+1, zTmpname); if( rc!=SQLITE_OK ){ return rc; @@ -5028,7 +5064,7 @@ static int unixOpen( #if OS_VXWORKS zPath = zName; #else - unlink(zName); + osUnlink(zName); #endif } #if SQLITE_ENABLE_LOCKING_STYLE @@ -5037,19 +5073,6 @@ static int unixOpen( } #endif - if( isOpenDirectory ){ - rc = openDirectory(zPath, &dirfd); - if( rc!=SQLITE_OK ){ - /* It is safe to close fd at this point, because it is guaranteed not - ** to be open on a database file. If it were open on a database file, - ** it would not be safe to close as this would release any locks held - ** on the file by this process. */ - assert( eType!=SQLITE_OPEN_MAIN_DB ); - robust_close(p, fd, __LINE__); - goto open_finished; - } - } - #ifdef FD_CLOEXEC osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif @@ -5058,10 +5081,8 @@ static int unixOpen( #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE - struct statfs fsInfo; if( fstatfs(fd, &fsInfo) == -1 ){ ((unixFile*)pFile)->lastErrno = errno; - if( dirfd>=0 ) robust_close(p, dirfd, __LINE__); robust_close(p, fd, __LINE__); return SQLITE_IOERR_ACCESS; } @@ -5083,7 +5104,6 @@ static int unixOpen( if( envforce!=NULL ){ useProxy = atoi(envforce)>0; }else{ - struct statfs fsInfo; if( statfs(zPath, &fsInfo) == -1 ){ /* In theory, the close(fd) call is sub-optimal. If the file opened ** with fd is a database file, and there are other connections open @@ -5093,9 +5113,6 @@ static int unixOpen( ** not while other file descriptors opened by the same process on ** the same file are working. */ p->lastErrno = errno; - if( dirfd>=0 ){ - robust_close(p, dirfd, __LINE__); - } robust_close(p, fd, __LINE__); rc = SQLITE_IOERR_ACCESS; goto open_finished; @@ -5103,7 +5120,7 @@ static int unixOpen( useProxy = !(fsInfo.f_flags&MNT_LOCAL); } if( useProxy ){ - rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, + rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, isDelete, isReadonly); if( rc==SQLITE_OK ){ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); @@ -5121,7 +5138,7 @@ static int unixOpen( } #endif - rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, + rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, isDelete, isReadonly); open_finished: if( rc!=SQLITE_OK ){ @@ -5143,13 +5160,13 @@ static int unixDelete( int rc = SQLITE_OK; UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); - if( unlink(zPath)==(-1) && errno!=ENOENT ){ + if( osUnlink(zPath)==(-1) && errno!=ENOENT ){ return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); } #ifndef SQLITE_DISABLE_DIRSYNC if( dirSync ){ int fd; - rc = openDirectory(zPath, &fd); + rc = osOpenDirectory(zPath, &fd); if( rc==SQLITE_OK ){ #if OS_VXWORKS if( fsync(fd)==-1 ) @@ -5160,6 +5177,8 @@ static int unixDelete( rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } robust_close(0, fd, __LINE__); + }else if( rc==SQLITE_CANTOPEN ){ + rc = SQLITE_OK; } } #endif @@ -5202,7 +5221,7 @@ static int unixAccess( *pResOut = (osAccess(zPath, amode)==0); if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){ struct stat buf; - if( 0==stat(zPath, &buf) && buf.st_size==0 ){ + if( 0==osStat(zPath, &buf) && buf.st_size==0 ){ *pResOut = 0; } } @@ -5400,10 +5419,12 @@ int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** -** On success, return 0. Return 1 if the time and date cannot be found. +** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date +** cannot be found. */ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; + int rc = SQLITE_OK; #if defined(NO_GETTOD) time_t t; time(&t); @@ -5414,8 +5435,11 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000; #else struct timeval sNow; - gettimeofday(&sNow, 0); - *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; + if( gettimeofday(&sNow, 0)==0 ){ + *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; + }else{ + rc = SQLITE_ERROR; + } #endif #ifdef SQLITE_TEST @@ -5424,7 +5448,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ } #endif UNUSED_PARAMETER(NotUsed); - return 0; + return rc; } /* @@ -5433,11 +5457,12 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ ** return 0. Return 1 if the time and date cannot be found. */ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){ - sqlite3_int64 i; + sqlite3_int64 i = 0; + int rc; UNUSED_PARAMETER(NotUsed); - unixCurrentTimeInt64(0, &i); + rc = unixCurrentTimeInt64(0, &i); *prNow = i/86400000.0; - return 0; + return rc; } /* @@ -5721,7 +5746,6 @@ static int proxyCreateUnixFile( int islockfile /* if non zero missing dirs will be created */ ) { int fd = -1; - int dirfd = -1; unixFile *pNew; int rc = SQLITE_OK; int openFlags = O_RDWR | O_CREAT; @@ -5786,7 +5810,7 @@ static int proxyCreateUnixFile( pUnused->flags = openFlags; pNew->pUnused = pUnused; - rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0, 0); + rc = fillInUnixFile(&dummyVfs, fd, 0, (sqlite3_file*)pNew, path, 0, 0, 0); if( rc==SQLITE_OK ){ *ppFile = pNew; return SQLITE_OK; @@ -5826,6 +5850,8 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){ return SQLITE_IOERR; } } +#else + UNUSED_PARAMETER(pError); #endif #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ @@ -5900,7 +5926,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ end_breaklock: if( rc ){ if( fd>=0 ){ - unlink(tPath); + osUnlink(tPath); robust_close(pFile, fd, __LINE__); } fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg); @@ -5918,6 +5944,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ int nTries = 0; struct timespec conchModTime; + memset(&conchModTime, 0, sizeof(conchModTime)); do { rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); nTries ++; @@ -6149,11 +6176,12 @@ static int proxyTakeConch(unixFile *pFile){ end_takeconch: OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); if( rc==SQLITE_OK && pFile->openFlags ){ + int fd; if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); } pFile->h = -1; - int fd = robust_open(pCtx->dbPath, pFile->openFlags, + fd = robust_open(pCtx->dbPath, pFile->openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS); OSTRACE(("TRANSPROXY: OPEN %d\n", fd)); if( fd>=0 ){ @@ -6723,7 +6751,7 @@ int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==16 ); + assert( ArraySize(aSyscall)==18 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ diff --git a/src/os_win.c b/src/os_win.c index bd0f2f21..45180304 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -102,8 +102,9 @@ struct winFile { const sqlite3_io_methods *pMethod; /*** Must be first ***/ sqlite3_vfs *pVfs; /* The VFS used to open this file */ HANDLE h; /* Handle for accessing the file */ - unsigned char locktype; /* Type of lock currently held on this file */ + u8 locktype; /* Type of lock currently held on this file */ short sharedLockByte; /* Randomly chosen byte used as a shared lock */ + u8 bPersistWal; /* True to persist WAL files */ DWORD lastErrno; /* The Windows errno from the last I/O error */ DWORD sectorSize; /* Sector size of the device file is on */ winShm *pShm; /* Instance of shared memory on this file */ @@ -118,6 +119,76 @@ struct winFile { #endif }; +/* + * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the + * various Win32 API heap functions instead of our own. + */ +#ifdef SQLITE_WIN32_MALLOC +/* + * The initial size of the Win32-specific heap. This value may be zero. + */ +#ifndef SQLITE_WIN32_HEAP_INIT_SIZE +# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \ + (SQLITE_DEFAULT_PAGE_SIZE) + 4194304) +#endif + +/* + * The maximum size of the Win32-specific heap. This value may be zero. + */ +#ifndef SQLITE_WIN32_HEAP_MAX_SIZE +# define SQLITE_WIN32_HEAP_MAX_SIZE (0) +#endif + +/* + * The extra flags to use in calls to the Win32 heap APIs. This value may be + * zero for the default behavior. + */ +#ifndef SQLITE_WIN32_HEAP_FLAGS +# define SQLITE_WIN32_HEAP_FLAGS (0) +#endif + +/* +** The winMemData structure stores information required by the Win32-specific +** sqlite3_mem_methods implementation. +*/ +typedef struct winMemData winMemData; +struct winMemData { +#ifndef NDEBUG + u32 magic; /* Magic number to detect structure corruption. */ +#endif + HANDLE hHeap; /* The handle to our heap. */ + BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */ +}; + +#ifndef NDEBUG +#define WINMEM_MAGIC 0x42b2830b +#endif + +static struct winMemData win_mem_data = { +#ifndef NDEBUG + WINMEM_MAGIC, +#endif + NULL, FALSE +}; + +#ifndef NDEBUG +#define winMemAssertMagic() assert( win_mem_data.magic==WINMEM_MAGIC ) +#else +#define winMemAssertMagic() +#endif + +#define winMemGetHeap() win_mem_data.hHeap + +static void *winMemMalloc(int nBytes); +static void winMemFree(void *pPrior); +static void *winMemRealloc(void *pPrior, int nBytes); +static int winMemSize(void *p); +static int winMemRoundup(int n); +static int winMemInit(void *pAppData); +static void winMemShutdown(void *pAppData); + +const sqlite3_mem_methods *sqlite3MemGetWin32(void); +#endif /* SQLITE_WIN32_MALLOC */ /* ** Forward prototypes. @@ -170,6 +241,188 @@ static int sqlite3_os_type = 0; } #endif /* SQLITE_OS_WINCE */ +#ifdef SQLITE_WIN32_MALLOC +/* +** Allocate nBytes of memory. +*/ +static void *winMemMalloc(int nBytes){ + HANDLE hHeap; + void *p; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#ifdef SQLITE_WIN32_MALLOC_VALIDATE + assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); +#endif + assert( nBytes>=0 ); + p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); + if( !p ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%d), heap=%p", + nBytes, GetLastError(), (void*)hHeap); + } + return p; +} + +/* +** Free memory. +*/ +static void winMemFree(void *pPrior){ + HANDLE hHeap; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#ifdef SQLITE_WIN32_MALLOC_VALIDATE + assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); +#endif + if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ + if( !HeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%d), heap=%p", + pPrior, GetLastError(), (void*)hHeap); + } +} + +/* +** Change the size of an existing memory allocation +*/ +static void *winMemRealloc(void *pPrior, int nBytes){ + HANDLE hHeap; + void *p; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#ifdef SQLITE_WIN32_MALLOC_VALIDATE + assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); +#endif + assert( nBytes>=0 ); + if( !pPrior ){ + p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); + }else{ + p = HeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes); + } + if( !p ){ + sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%d), heap=%p", + pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, GetLastError(), + (void*)hHeap); + } + return p; +} + +/* +** Return the size of an outstanding allocation, in bytes. +*/ +static int winMemSize(void *p){ + HANDLE hHeap; + SIZE_T n; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#ifdef SQLITE_WIN32_MALLOC_VALIDATE + assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); +#endif + if( !p ) return 0; + n = HeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p); + if( n==(SIZE_T)-1 ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%d), heap=%p", + p, GetLastError(), (void*)hHeap); + return 0; + } + return (int)n; +} + +/* +** Round up a request size to the next valid allocation size. +*/ +static int winMemRoundup(int n){ + return n; +} + +/* +** Initialize this module. +*/ +static int winMemInit(void *pAppData){ + winMemData *pWinMemData = (winMemData *)pAppData; + + if( !pWinMemData ) return SQLITE_ERROR; + assert( pWinMemData->magic==WINMEM_MAGIC ); + if( !pWinMemData->hHeap ){ + pWinMemData->hHeap = HeapCreate(SQLITE_WIN32_HEAP_FLAGS, + SQLITE_WIN32_HEAP_INIT_SIZE, + SQLITE_WIN32_HEAP_MAX_SIZE); + if( !pWinMemData->hHeap ){ + sqlite3_log(SQLITE_NOMEM, + "failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u", + GetLastError(), SQLITE_WIN32_HEAP_FLAGS, SQLITE_WIN32_HEAP_INIT_SIZE, + SQLITE_WIN32_HEAP_MAX_SIZE); + return SQLITE_NOMEM; + } + pWinMemData->bOwned = TRUE; + } + assert( pWinMemData->hHeap!=0 ); + assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); +#ifdef SQLITE_WIN32_MALLOC_VALIDATE + assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); +#endif + return SQLITE_OK; +} + +/* +** Deinitialize this module. +*/ +static void winMemShutdown(void *pAppData){ + winMemData *pWinMemData = (winMemData *)pAppData; + + if( !pWinMemData ) return; + if( pWinMemData->hHeap ){ + assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); +#ifdef SQLITE_WIN32_MALLOC_VALIDATE + assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); +#endif + if( pWinMemData->bOwned ){ + if( !HeapDestroy(pWinMemData->hHeap) ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p", + GetLastError(), (void*)pWinMemData->hHeap); + } + pWinMemData->bOwned = FALSE; + } + pWinMemData->hHeap = NULL; + } +} + +/* +** Populate the low-level memory allocation function pointers in +** sqlite3GlobalConfig.m with pointers to the routines in this file. The +** arguments specify the block of memory to manage. +** +** This routine is only called by sqlite3_config(), and therefore +** is not required to be threadsafe (it is not). +*/ +const sqlite3_mem_methods *sqlite3MemGetWin32(void){ + static const sqlite3_mem_methods winMemMethods = { + winMemMalloc, + winMemFree, + winMemRealloc, + winMemSize, + winMemRoundup, + winMemInit, + winMemShutdown, + &win_mem_data + }; + return &winMemMethods; +} + +void sqlite3MemSetDefault(void){ + sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32()); +} +#endif /* SQLITE_WIN32_MALLOC */ + /* ** Convert a UTF-8 string to microsoft unicode (UTF-16?). ** @@ -402,6 +655,54 @@ static int winLogErrorAtLine( return errcode; } +/* +** The number of times that a ReadFile(), WriteFile(), and DeleteFile() +** will be retried following a locking error - probably caused by +** antivirus software. Also the initial delay before the first retry. +** The delay increases linearly with each retry. +*/ +#ifndef SQLITE_WIN32_IOERR_RETRY +# define SQLITE_WIN32_IOERR_RETRY 10 +#endif +#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY +# define SQLITE_WIN32_IOERR_RETRY_DELAY 25 +#endif +static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY; +static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; + +/* +** If a ReadFile() or WriteFile() error occurs, invoke this routine +** to see if it should be retried. Return TRUE to retry. Return FALSE +** to give up with an error. +*/ +static int retryIoerr(int *pnRetry){ + DWORD e; + if( *pnRetry>=win32IoerrRetry ){ + return 0; + } + e = GetLastError(); + if( e==ERROR_ACCESS_DENIED || + e==ERROR_LOCK_VIOLATION || + e==ERROR_SHARING_VIOLATION ){ + Sleep(win32IoerrRetryDelay*(1+*pnRetry)); + ++*pnRetry; + return 1; + } + return 0; +} + +/* +** Log a I/O error retry episode. +*/ +static void logIoerr(int nRetry){ + if( nRetry ){ + sqlite3_log(SQLITE_IOERR, + "delayed %dms for lock/sharing conflict", + win32IoerrRetryDelay*nRetry*(nRetry+1)/2 + ); + } +} + #if SQLITE_OS_WINCE /************************************************************************* ** This section contains code for WinCE only. @@ -820,6 +1121,7 @@ static int winRead( ){ winFile *pFile = (winFile*)id; /* file handle */ DWORD nRead; /* Number of bytes actually read from file */ + int nRetry = 0; /* Number of retrys */ assert( id!=0 ); SimulateIOError(return SQLITE_IOERR_READ); @@ -828,10 +1130,12 @@ static int winRead( if( seekWinFile(pFile, offset) ){ return SQLITE_FULL; } - if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ + while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ + if( retryIoerr(&nRetry) ) continue; pFile->lastErrno = GetLastError(); return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath); } + logIoerr(nRetry); if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); @@ -853,6 +1157,7 @@ static int winWrite( ){ int rc; /* True if error has occured, else false */ winFile *pFile = (winFile*)id; /* File handle */ + int nRetry = 0; /* Number of retries */ assert( amt>0 ); assert( pFile ); @@ -867,7 +1172,12 @@ static int winWrite( int nRem = amt; /* Number of bytes yet to be written */ DWORD nWrite; /* Bytes written by each WriteFile() call */ - while( nRem>0 && WriteFile(pFile->h, aRem, nRem, &nWrite, 0) && nWrite>0 ){ + while( nRem>0 ){ + if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){ + if( retryIoerr(&nRetry) ) continue; + break; + } + if( nWrite<=0 ) break; aRem += nWrite; nRem -= nWrite; } @@ -883,6 +1193,8 @@ static int winWrite( return SQLITE_FULL; } return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath); + }else{ + logIoerr(nRetry); } return SQLITE_OK; } @@ -904,7 +1216,7 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ ** actual file size after the operation may be larger than the requested ** size). */ - if( pFile->szChunk ){ + if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } @@ -933,9 +1245,19 @@ int sqlite3_fullsync_count = 0; ** Make sure all writes to a particular file are committed to disk. */ static int winSync(sqlite3_file *id, int flags){ -#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG) - winFile *pFile = (winFile*)id; +#ifndef SQLITE_NO_SYNC + /* + ** Used only when SQLITE_NO_SYNC is not defined. + */ BOOL rc; +#endif +#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \ + (defined(SQLITE_TEST) && defined(SQLITE_DEBUG)) + /* + ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or + ** OSTRACE() macros. + */ + winFile *pFile = (winFile*)id; #else UNUSED_PARAMETER(id); #endif @@ -1276,29 +1598,62 @@ static int winUnlock(sqlite3_file *id, int locktype){ ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ + winFile *pFile = (winFile*)id; switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { - *(int*)pArg = ((winFile*)id)->locktype; + *(int*)pArg = pFile->locktype; return SQLITE_OK; } case SQLITE_LAST_ERRNO: { - *(int*)pArg = (int)((winFile*)id)->lastErrno; + *(int*)pArg = (int)pFile->lastErrno; return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { - ((winFile*)id)->szChunk = *(int *)pArg; + pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { - sqlite3_int64 sz = *(sqlite3_int64*)pArg; - SimulateIOErrorBenign(1); - winTruncate(id, sz); - SimulateIOErrorBenign(0); + if( pFile->szChunk>0 ){ + sqlite3_int64 oldSz; + int rc = winFileSize(id, &oldSz); + if( rc==SQLITE_OK ){ + sqlite3_int64 newSz = *(sqlite3_int64*)pArg; + if( newSz>oldSz ){ + SimulateIOErrorBenign(1); + rc = winTruncate(id, newSz); + SimulateIOErrorBenign(0); + } + } + return rc; + } + return SQLITE_OK; + } + case SQLITE_FCNTL_PERSIST_WAL: { + int bPersist = *(int*)pArg; + if( bPersist<0 ){ + *(int*)pArg = pFile->bPersistWal; + }else{ + pFile->bPersistWal = bPersist!=0; + } return SQLITE_OK; } case SQLITE_FCNTL_SYNC_OMITTED: { return SQLITE_OK; } + case SQLITE_FCNTL_WIN32_AV_RETRY: { + int *a = (int*)pArg; + if( a[0]>0 ){ + win32IoerrRetry = a[0]; + }else{ + a[0] = win32IoerrRetry; + } + if( a[1]>0 ){ + win32IoerrRetryDelay = a[1]; + }else{ + a[1] = win32IoerrRetryDelay; + } + return SQLITE_OK; + } } return SQLITE_NOTFOUND; } @@ -2107,6 +2462,7 @@ static int winOpen( winFile *pFile = (winFile*)id; void *zConverted; /* Filename in OS encoding */ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ + int cnt = 0; /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. @@ -2226,31 +2582,31 @@ static int winOpen( #endif if( isNT() ){ - h = CreateFileW((WCHAR*)zConverted, - dwDesiredAccess, - dwShareMode, - NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL - ); + while( (h = CreateFileW((WCHAR*)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL))==INVALID_HANDLE_VALUE && + retryIoerr(&cnt) ){} /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. ** Since the ASCII version of these Windows API do not exist for WINCE, ** it's important to not reference them for WINCE builds. */ #if SQLITE_OS_WINCE==0 }else{ - h = CreateFileA((char*)zConverted, - dwDesiredAccess, - dwShareMode, - NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL - ); + while( (h = CreateFileA((char*)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL))==INVALID_HANDLE_VALUE && + retryIoerr(&cnt) ){} #endif } + logIoerr(cnt); + OSTRACE(("OPEN %d %s 0x%lx %s\n", h, zName, dwDesiredAccess, h==INVALID_HANDLE_VALUE ? "failed" : "ok")); @@ -2259,7 +2615,7 @@ static int winOpen( pFile->lastErrno = GetLastError(); winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name); free(zConverted); - if( isReadWrite ){ + if( isReadWrite && !isExclusive ){ return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); }else{ @@ -2316,15 +2672,13 @@ static int winOpen( ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving ** up and returning an error. */ -#define MX_DELETION_ATTEMPTS 5 static int winDelete( sqlite3_vfs *pVfs, /* Not used on win32 */ const char *zFilename, /* Name of file to delete */ int syncDir /* Not used on win32 */ ){ int cnt = 0; - DWORD rc; - DWORD error = 0; + int rc; void *zConverted; UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(syncDir); @@ -2335,34 +2689,30 @@ static int winDelete( return SQLITE_NOMEM; } if( isNT() ){ - do{ - DeleteFileW(zConverted); - }while( ( ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES) - || ((error = GetLastError()) == ERROR_ACCESS_DENIED)) - && (++cnt < MX_DELETION_ATTEMPTS) - && (Sleep(100), 1) ); + rc = 1; + while( GetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES && + (rc = DeleteFileW(zConverted))==0 && retryIoerr(&cnt) ){} + rc = rc ? SQLITE_OK : SQLITE_ERROR; /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. ** Since the ASCII version of these Windows API do not exist for WINCE, ** it's important to not reference them for WINCE builds. */ #if SQLITE_OS_WINCE==0 }else{ - do{ - DeleteFileA(zConverted); - }while( ( ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES) - || ((error = GetLastError()) == ERROR_ACCESS_DENIED)) - && (++cnt < MX_DELETION_ATTEMPTS) - && (Sleep(100), 1) ); + rc = 1; + while( GetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES && + (rc = DeleteFileA(zConverted))==0 && retryIoerr(&cnt) ){} + rc = rc ? SQLITE_OK : SQLITE_ERROR; #endif } + if( rc ){ + rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename); + }else{ + logIoerr(cnt); + } free(zConverted); - OSTRACE(("DELETE \"%s\" %s\n", zFilename, - ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ? - "ok" : "failed" )); - - return ( (rc == INVALID_FILE_ATTRIBUTES) - && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : - winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename); + OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" ))); + return rc; } /* @@ -2385,11 +2735,13 @@ static int winAccess( return SQLITE_NOMEM; } if( isNT() ){ + int cnt = 0; WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); - if( GetFileAttributesExW((WCHAR*)zConverted, + while( !(rc = GetFileAttributesExW((WCHAR*)zConverted, GetFileExInfoStandard, - &sAttrData) ){ + &sAttrData)) && retryIoerr(&cnt) ){} + if( rc ){ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file ** as if it does not exist. */ @@ -2401,6 +2753,7 @@ static int winAccess( attr = sAttrData.dwFileAttributes; } }else{ + logIoerr(cnt); if( GetLastError()!=ERROR_FILE_NOT_FOUND ){ winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename); free(zConverted); @@ -2425,7 +2778,8 @@ static int winAccess( rc = attr!=INVALID_FILE_ATTRIBUTES; break; case SQLITE_ACCESS_READWRITE: - rc = (attr & FILE_ATTRIBUTE_READONLY)==0; + rc = attr!=INVALID_FILE_ATTRIBUTES && + (attr & FILE_ATTRIBUTE_READONLY)==0; break; default: assert(!"Invalid flags argument"); @@ -2627,7 +2981,7 @@ static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ UNUSED_PARAMETER(pVfs); getLastErrorMsg(nBuf, zBufOut); } -void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ +static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ UNUSED_PARAMETER(pVfs); #if SQLITE_OS_WINCE /* The GetProcAddressA() routine is only available on wince. */ @@ -2638,7 +2992,7 @@ void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ return (void(*)(void))GetProcAddress((HANDLE)pHandle, zSymbol); #endif } -void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ +static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ UNUSED_PARAMETER(pVfs); FreeLibrary((HANDLE)pHandle); } @@ -2712,7 +3066,8 @@ int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** -** On success, return 0. Return 1 if the time and date cannot be found. +** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date +** cannot be found. */ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ /* FILETIME structure is a 64-bit value representing the number of @@ -2732,7 +3087,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ GetSystemTime(&time); /* if SystemTimeToFileTime() fails, it returns zero. */ if (!SystemTimeToFileTime(&time,&ft)){ - return 1; + return SQLITE_ERROR; } #else GetSystemTimeAsFileTime( &ft ); @@ -2748,7 +3103,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ } #endif UNUSED_PARAMETER(pVfs); - return 0; + return SQLITE_OK; } /* @@ -2756,7 +3111,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ +static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ int rc; sqlite3_int64 i; rc = winCurrentTimeInt64(pVfs, &i); diff --git a/src/pager.c b/src/pager.c index fd74ea4f..ad6f8310 100644 --- a/src/pager.c +++ b/src/pager.c @@ -670,8 +670,8 @@ struct Pager { char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ + int nHit, nMiss; /* Total cache hits and misses */ #ifdef SQLITE_TEST - int nHit, nMiss; /* Cache hits and missing */ int nRead, nWrite; /* Database pages read/written */ #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ @@ -2703,7 +2703,6 @@ static int pager_playback(Pager *pPager, int isHot){ rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ - rc = SQLITE_OK; pPager->journalOff = szJ; break; }else if( rc==SQLITE_IOERR_SHORT_READ ){ @@ -2965,6 +2964,7 @@ static int pagerWalFrames( #endif assert( pPager->pWal ); + assert( pList ); #ifdef SQLITE_DEBUG /* Verify that the page list is in accending order */ for(p=pList; p && p->pDirty; p=p->pDirty){ @@ -3739,6 +3739,7 @@ static int pagerSyncHotJournal(Pager *pPager){ int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; + assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); /* pPager->errCode = 0; */ @@ -4168,7 +4169,7 @@ static int pagerStress(void *p, PgHdr *pPg){ ** ** Spilling is also prohibited when in an error state since that could ** lead to database corruption. In the current implementaton it - ** is impossible for sqlite3PCacheFetch() to be called with createFlag==1 + ** is impossible for sqlite3PcacheFetch() to be called with createFlag==1 ** while in the error state, hence it is impossible for this routine to ** be called in the error state. Nevertheless, we include a NEVER() ** test for the error state as a safeguard against future changes. @@ -5004,14 +5005,13 @@ int sqlite3PagerAcquire( /* In this case the pcache already contains an initialized copy of ** the page. Return without further ado. */ assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) ); - PAGER_INCR(pPager->nHit); + pPager->nHit++; return SQLITE_OK; }else{ /* The pager cache has created a new page. Its content needs to ** be initialized. */ - PAGER_INCR(pPager->nMiss); pPg = *ppPage; pPg->pPager = pPager; @@ -5047,6 +5047,7 @@ int sqlite3PagerAcquire( IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ assert( pPg->pPager==pPager ); + pPager->nMiss++; rc = readDbPage(pPg); if( rc!=SQLITE_OK ){ goto pager_acquire_err; @@ -6081,6 +6082,31 @@ int *sqlite3PagerStats(Pager *pPager){ } #endif +/* +** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or +** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the +** current cache hit or miss count, according to the value of eStat. If the +** reset parameter is non-zero, the cache hit or miss count is zeroed before +** returning. +*/ +void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ + int *piStat; + + assert( eStat==SQLITE_DBSTATUS_CACHE_HIT + || eStat==SQLITE_DBSTATUS_CACHE_MISS + ); + if( eStat==SQLITE_DBSTATUS_CACHE_HIT ){ + piStat = &pPager->nHit; + }else{ + piStat = &pPager->nMiss; + } + + *pnVal += *piStat; + if( reset ){ + *piStat = 0; + } +} + /* ** Return true if this is an in-memory pager. */ @@ -6810,6 +6836,13 @@ int sqlite3PagerCloseWal(Pager *pPager){ return rc; } +/* +** Unless this is an in-memory or temporary database, clear the pager cache. +*/ +void sqlite3PagerClearCache(Pager *pPager){ + if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager); +} + #ifdef SQLITE_HAS_CODEC /* ** This function is called by the wal module when writing page content diff --git a/src/pager.h b/src/pager.h index eab7ddaf..e36e6c2e 100644 --- a/src/pager.h +++ b/src/pager.h @@ -155,6 +155,8 @@ const char *sqlite3PagerJournalname(Pager*); int sqlite3PagerNosync(Pager*); void *sqlite3PagerTempSpace(Pager*); int sqlite3PagerIsMemdb(Pager*); +void sqlite3PagerCacheStat(Pager *, int, int, int *); +void sqlite3PagerClearCache(Pager *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); diff --git a/src/pcache1.c b/src/pcache1.c index e47265a2..077a7b21 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -24,6 +24,7 @@ typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; + /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set ** of one or more PCaches that are able to recycle each others unpinned ** pages when they are under memory pressure. A PGroup is an instance of @@ -288,15 +289,22 @@ static int pcache1MemSize(void *p){ */ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){ int nByte = sizeof(PgHdr1) + pCache->szPage; - void *pPg = pcache1Alloc(nByte); - PgHdr1 *p; + PgHdr1 *p = 0; + void *pPg; + + /* The group mutex must be released before pcache1Alloc() is called. This + ** is because it may call sqlite3_release_memory(), which assumes that + ** this mutex is not held. */ + assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); + pcache1LeaveMutex(pCache->pGroup); + pPg = pcache1Alloc(nByte); + pcache1EnterMutex(pCache->pGroup); + if( pPg ){ p = PAGE_TO_PGHDR1(pCache, pPg); if( pCache->bPurgeable ){ pCache->pGroup->nCurrentPage++; } - }else{ - p = 0; } return p; } @@ -311,10 +319,11 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){ static void pcache1FreePage(PgHdr1 *p){ if( ALWAYS(p) ){ PCache1 *pCache = p->pCache; + assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) ); + pcache1Free(PGHDR1_TO_PAGE(p)); if( pCache->bPurgeable ){ pCache->pGroup->nCurrentPage--; } - pcache1Free(PGHDR1_TO_PAGE(p)); } } @@ -752,9 +761,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){ */ if( !pPage ){ if( createFlag==1 ) sqlite3BeginBenignMalloc(); - pcache1LeaveMutex(pGroup); pPage = pcache1AllocPage(pCache); - pcache1EnterMutex(pGroup); if( createFlag==1 ) sqlite3EndBenignMalloc(); } diff --git a/src/pragma.c b/src/pragma.c index dd6e059d..7c20a89e 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -467,7 +467,7 @@ void sqlite3Pragma( if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3CodeVerifySchema(pParse, iDb); iReg = ++pParse->nMem; - if( zLeft[0]=='p' ){ + if( sqlite3Tolower(zLeft[0])=='p' ){ sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg); }else{ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight)); @@ -533,8 +533,10 @@ void sqlite3Pragma( int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */ int ii; /* Loop counter */ - /* Force the schema to be loaded on all databases. This cases all - ** database files to be opened and the journal_modes set. */ + /* Force the schema to be loaded on all databases. This causes all + ** database files to be opened and the journal_modes set. This is + ** necessary because subsequent processing must know if the databases + ** are in WAL mode. */ if( sqlite3ReadSchema(pParse) ){ goto pragma_out; } @@ -1078,7 +1080,7 @@ void sqlite3Pragma( { OP_ResultRow, 3, 1, 0}, }; - int isQuick = (zLeft[0]=='q'); + int isQuick = (sqlite3Tolower(zLeft[0])=='q'); /* Initialize the VDBE program */ if( sqlite3ReadSchema(pParse) ) goto pragma_out; diff --git a/src/printf.c b/src/printf.c index 2a3dd81d..0babee51 100644 --- a/src/printf.c +++ b/src/printf.c @@ -7,48 +7,10 @@ ** ************************************************************************** ** -** The following modules is an enhanced replacement for the "printf" subroutines -** found in the standard C library. The following enhancements are -** supported: -** -** + Additional functions. The standard set of "printf" functions -** includes printf, fprintf, sprintf, vprintf, vfprintf, and -** vsprintf. This module adds the following: -** -** * snprintf -- Works like sprintf, but has an extra argument -** which is the size of the buffer written to. -** -** * mprintf -- Similar to sprintf. Writes output to memory -** obtained from malloc. -** -** * xprintf -- Calls a function to dispose of output. -** -** * nprintf -- No output, but returns the number of characters -** that would have been output by printf. -** -** * A v- version (ex: vsnprintf) of every function is also -** supplied. -** -** + A few extensions to the formatting notation are supported: -** -** * The "=" flag (similar to "-") causes the output to be -** be centered in the appropriately sized field. -** -** * The %b field outputs an integer in binary notation. -** -** * The %c field now accepts a precision. The character output -** is repeated by the number of times the precision specifies. -** -** * The %' field works like %c, but takes as its character the -** next character of the format string, instead of the next -** argument. For example, printf("%.78'-") prints 78 minus -** signs, the same as printf("%.78c",'-'). -** -** + When compiled using GCC on a SPARC, this version of printf is -** faster than the library printf for SUN OS 4.1. -** -** + All functions are fully reentrant. -** +** This file contains code for a set of "printf"-like routines. These +** routines format strings much like the printf() from the standard C +** library, though the implementation here has enhancements to support +** SQLlite. */ #include "sqliteInt.h" @@ -187,43 +149,15 @@ static void appendSpace(StrAccum *pAccum, int N){ /* ** On machines with a small stack size, you can redefine the -** SQLITE_PRINT_BUF_SIZE to be less than 350. +** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired. */ #ifndef SQLITE_PRINT_BUF_SIZE -# if defined(SQLITE_SMALL_STACK) -# define SQLITE_PRINT_BUF_SIZE 50 -# else -# define SQLITE_PRINT_BUF_SIZE 350 -# endif +# define SQLITE_PRINT_BUF_SIZE 70 #endif #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ /* -** The root program. All variations call this core. -** -** INPUTS: -** func This is a pointer to a function taking three arguments -** 1. A pointer to anything. Same as the "arg" parameter. -** 2. A pointer to the list of characters to be output -** (Note, this list is NOT null terminated.) -** 3. An integer number of characters to be output. -** (Note: This number might be zero.) -** -** arg This is the pointer to anything which will be passed as the -** first argument to "func". Use it for whatever you like. -** -** fmt This is the format string, as in the usual print. -** -** ap This is a pointer to a list of arguments. Same as in -** vfprint. -** -** OUTPUTS: -** The return value is the total number of characters sent to -** the function "func". Returns -1 on a error. -** -** Note that the order in which automatic variables are declared below -** seems to make a big difference in determining how fast this beast -** will run. +** Render a string given by "fmt" into the StrAccum object. */ void sqlite3VXPrintf( StrAccum *pAccum, /* Accumulate results here */ @@ -246,23 +180,23 @@ void sqlite3VXPrintf( etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ etByte done; /* Loop termination flag */ + etByte xtype = 0; /* Conversion paradigm */ + char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ sqlite_uint64 longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ const et_info *infop; /* Pointer to the appropriate info structure */ - char buf[etBUFSIZE]; /* Conversion buffer */ - char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ - etByte xtype = 0; /* Conversion paradigm */ - char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ + char *zOut; /* Rendering buffer */ + int nOut; /* Size of the rendering buffer */ + char *zExtra; /* Malloced memory used by some conversion */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ + int nsd; /* Number of significant digits returned */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ - etByte flag_exp; /* True to force display of the exponent */ - int nsd; /* Number of significant digits returned */ #endif + char buf[etBUFSIZE]; /* Conversion buffer */ - length = 0; bufpt = 0; for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ @@ -307,9 +241,6 @@ void sqlite3VXPrintf( c = *++fmt; } } - if( width > etBUFSIZE-10 ){ - width = etBUFSIZE-10; - } /* Get the precision */ if( c=='.' ){ precision = 0; @@ -356,12 +287,6 @@ void sqlite3VXPrintf( } zExtra = 0; - - /* Limit the precision to prevent overflowing buf[] during conversion */ - if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){ - precision = etBUFSIZE-40; - } - /* ** At this point, variables are initialized as follows: ** @@ -426,16 +351,26 @@ void sqlite3VXPrintf( if( flag_zeropad && precisionmallocFailed = 1; + return; + } + } + bufpt = &zOut[nOut-1]; if( xtype==etORDINAL ){ static const char zOrd[] = "thstndrd"; int x = (int)(longvalue % 10); if( x>=4 || (longvalue/10)%10==1 ){ x = 0; } - buf[etBUFSIZE-3] = zOrd[x*2]; - buf[etBUFSIZE-2] = zOrd[x*2+1]; - bufpt -= 2; + *(--bufpt) = zOrd[x*2+1]; + *(--bufpt) = zOrd[x*2]; } { register const char *cset; /* Use registers for speed */ @@ -447,7 +382,7 @@ void sqlite3VXPrintf( longvalue = longvalue/base; }while( longvalue>0 ); } - length = (int)(&buf[etBUFSIZE-1]-bufpt); + length = (int)(&zOut[nOut-1]-bufpt); for(idx=precision-length; idx>0; idx--){ *(--bufpt) = '0'; /* Zero pad */ } @@ -458,7 +393,7 @@ void sqlite3VXPrintf( pre = &aPrefix[infop->prefix]; for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; } - length = (int)(&buf[etBUFSIZE-1]-bufpt); + length = (int)(&zOut[nOut-1]-bufpt); break; case etFLOAT: case etEXP: @@ -468,7 +403,6 @@ void sqlite3VXPrintf( length = 0; #else if( precision<0 ) precision = 6; /* Set default precision */ - if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10; if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; @@ -516,7 +450,6 @@ void sqlite3VXPrintf( ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ - flag_exp = xtype==etEXP; if( xtype!=etFLOAT ){ realvalue += rounder; if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } @@ -537,6 +470,14 @@ void sqlite3VXPrintf( }else{ e2 = exp; } + if( e2+precision+width > etBUFSIZE - 15 ){ + bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 ); + if( bufpt==0 ){ + pAccum->mallocFailed = 1; + return; + } + } + zOut = bufpt; nsd = 0; flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; /* The sign in front of the number */ @@ -568,7 +509,7 @@ void sqlite3VXPrintf( /* Remove trailing zeros and the "." if no digits follow the "." */ if( flag_rtz && flag_dp ){ while( bufpt[-1]=='0' ) *(--bufpt) = 0; - assert( bufpt>buf ); + assert( bufpt>zOut ); if( bufpt[-1]=='.' ){ if( flag_altform2 ){ *(bufpt++) = '0'; @@ -578,7 +519,7 @@ void sqlite3VXPrintf( } } /* Add the "eNNN" suffix */ - if( flag_exp || xtype==etEXP ){ + if( xtype==etEXP ){ *(bufpt++) = aDigits[infop->charset]; if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; @@ -597,8 +538,8 @@ void sqlite3VXPrintf( /* The converted number is in buf[] and zero terminated. Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions. */ - length = (int)(bufpt-buf); - bufpt = buf; + length = (int)(bufpt-zOut); + bufpt = zOut; /* Special case: Add leading zeros if the flag_zeropad flag is ** set and we are not left justified */ @@ -736,9 +677,7 @@ void sqlite3VXPrintf( appendSpace(pAccum, nspace); } } - if( zExtra ){ - sqlite3_free(zExtra); - } + sqlite3_free(zExtra); }/* End for loop over the format string */ } /* End of function */ @@ -752,6 +691,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ testcase(p->mallocFailed); return; } + assert( p->zText!=0 || p->nChar==0 ); if( N<0 ){ N = sqlite3Strlen30(z); } @@ -783,7 +723,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ zNew = sqlite3_realloc(zOld, p->nAlloc); } if( zNew ){ - if( zOld==0 ) memcpy(zNew, p->zText, p->nChar); + if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; }else{ p->mallocFailed = 1; @@ -792,6 +732,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ } } } + assert( p->zText ); memcpy(&p->zText[p->nChar], z, N); p->nChar += N; } diff --git a/src/resolve.c b/src/resolve.c index 74d6aaef..6d857f00 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -98,6 +98,24 @@ static void resolveAlias( sqlite3DbFree(db, pDup); } + +/* +** Return TRUE if the name zCol occurs anywhere in the USING clause. +** +** Return FALSE if the USING clause is NULL or if it does not contain +** zCol. +*/ +static int nameInUsingClause(IdList *pUsing, const char *zCol){ + if( pUsing ){ + int k; + for(k=0; knId; k++){ + if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1; + } + } + return 0; +} + + /* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr @@ -189,7 +207,14 @@ static int lookupName( } for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ - IdList *pUsing; + /* If there has been exactly one prior match and this match + ** is for the right-hand table of a NATURAL JOIN or is in a + ** USING clause, then skip this match. + */ + if( cnt==1 ){ + if( pItem->jointype & JT_NATURAL ) continue; + if( nameInUsingClause(pItem->pUsing, zCol) ) continue; + } cnt++; pExpr->iTable = pItem->iCursor; pExpr->pTab = pTab; @@ -197,26 +222,6 @@ static int lookupName( pSchema = pTab->pSchema; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; - if( inSrc-1 ){ - if( pItem[1].jointype & JT_NATURAL ){ - /* If this match occurred in the left table of a natural join, - ** then skip the right table to avoid a duplicate match */ - pItem++; - i++; - }else if( (pUsing = pItem[1].pUsing)!=0 ){ - /* If this match occurs on a column that is in the USING clause - ** of a join, skip the search of the right table of the join - ** to avoid a duplicate match there. */ - int k; - for(k=0; knId; k++){ - if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){ - pItem++; - i++; - break; - } - } - } - } break; } } @@ -996,11 +1001,25 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ for(i=0; ipSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; if( pItem->pSelect ){ + NameContext *pNC; /* Used to iterate name contexts */ + int nRef = 0; /* Refcount for pOuterNC and outer contexts */ const char *zSavedContext = pParse->zAuthContext; + + /* Count the total number of references to pOuterNC and all of its + ** parent contexts. After resolving references to expressions in + ** pItem->pSelect, check if this value has changed. If so, then + ** SELECT statement pItem->pSelect must be correlated. Set the + ** pItem->isCorrelated flag if this is the case. */ + for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef; + if( pItem->zName ) pParse->zAuthContext = pItem->zName; sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; if( pParse->nErr || db->mallocFailed ) return WRC_Abort; + + for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef; + assert( pItem->isCorrelated==0 && nRef<=0 ); + pItem->isCorrelated = (nRef!=0); } } diff --git a/src/select.c b/src/select.c index 8dcfb84b..571a7782 100644 --- a/src/select.c +++ b/src/select.c @@ -65,6 +65,7 @@ Select *sqlite3SelectNew( pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); assert( db->mallocFailed || !pOffset || pLimit ); /* OFFSET implies LIMIT */ if( pNew==0 ){ + assert( db->mallocFailed ); pNew = &standin; memset(pNew, 0, sizeof(*pNew)); } @@ -89,7 +90,10 @@ Select *sqlite3SelectNew( clearSelect(db, pNew); if( pNew!=&standin ) sqlite3DbFree(db, pNew); pNew = 0; + }else{ + assert( pNew->pSrc!=0 || pParse->nErr>0 ); } + assert( pNew!=&standin ); return pNew; } @@ -419,12 +423,18 @@ static void pushOntoSorter( int nExpr = pOrderBy->nExpr; int regBase = sqlite3GetTempRange(pParse, nExpr+2); int regRecord = sqlite3GetTempReg(pParse); + int op; sqlite3ExprCacheClear(pParse); sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0); sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); - sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord); + if( pSelect->selFlags & SF_UseSorter ){ + op = OP_SorterInsert; + }else{ + op = OP_IdxInsert; + } + sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nExpr+2); if( pSelect->iLimit ){ @@ -893,9 +903,20 @@ static void generateSortTail( }else{ regRowid = sqlite3GetTempReg(pParse); } - addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); - codeOffset(v, p, addrContinue); - sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow); + if( p->selFlags & SF_UseSorter ){ + int regSortOut = ++pParse->nMem; + int ptab2 = pParse->nTab++; + sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2); + addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); + codeOffset(v, p, addrContinue); + sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut); + sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow); + sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); + }else{ + addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); + codeOffset(v, p, addrContinue); + sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow); + } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { @@ -948,7 +969,11 @@ static void generateSortTail( /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); - sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); + if( p->selFlags & SF_UseSorter ){ + sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); + }else{ + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); + } sqlite3VdbeResolveLabel(v, addrBreak); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0); @@ -1247,7 +1272,10 @@ static int selectColumnsFromExprList( }else{ Expr *pColExpr = p; /* The expression that is the result column name */ Table *pTab; /* Table associated with this expression */ - while( pColExpr->op==TK_DOT ) pColExpr = pColExpr->pRight; + while( pColExpr->op==TK_DOT ){ + pColExpr = pColExpr->pRight; + assert( pColExpr!=0 ); + } if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; @@ -3721,6 +3749,7 @@ int sqlite3Select( int distinct; /* Table to use for the distinct set */ int rc = 1; /* Value to return from this function */ int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ + int addrDistinctIndex; /* Address of an OP_OpenEphemeral instruction */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ @@ -3779,7 +3808,11 @@ int sqlite3Select( Select *pSub = pItem->pSelect; int isAggSub; - if( pSub==0 || pItem->isPopulated ) continue; + if( pSub==0 ) continue; + if( pItem->addrFillSub ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); + continue; + } /* Increment Parse.nHeight by the height of the largest expression ** tree refered to by this, the parent select. The child select @@ -3790,21 +3823,44 @@ int sqlite3Select( */ pParse->nHeight += sqlite3SelectExprHeight(p); - /* Check to see if the subquery can be absorbed into the parent. */ isAggSub = (pSub->selFlags & SF_Aggregate)!=0; if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ + /* This subquery can be absorbed into its parent. */ if( isAggSub ){ isAgg = 1; p->selFlags |= SF_Aggregate; } i = -1; }else{ + /* Generate a subroutine that will fill an ephemeral table with + ** the content of this subquery. pItem->addrFillSub will point + ** to the address of the generated subroutine. pItem->regReturn + ** is a register allocated to hold the subroutine return address + */ + int topAddr; + int onceAddr = 0; + int retAddr; + assert( pItem->addrFillSub==0 ); + pItem->regReturn = ++pParse->nMem; + topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); + pItem->addrFillSub = topAddr+1; + VdbeNoopComment((v, "materialize %s", pItem->pTab->zName)); + if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){ + /* If the subquery is no correlated and if we are not inside of + ** a trigger, then we only need to compute the value of the subquery + ** once. */ + int regOnce = ++pParse->nMem; + onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce); + } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - assert( pItem->isPopulated==0 ); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->isPopulated = 1; pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; + if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); + retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); + VdbeComment((v, "end %s", pItem->pTab->zName)); + sqlite3VdbeChangeP1(v, topAddr, retAddr); + } if( /*pParse->nErr ||*/ db->mallocFailed ){ goto select_end; @@ -3847,16 +3903,6 @@ int sqlite3Select( } #endif - /* If possible, rewrite the query to use GROUP BY instead of DISTINCT. - ** GROUP BY might use an index, DISTINCT never does. - */ - assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 ); - if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){ - p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); - pGroupBy = p->pGroupBy; - p->selFlags &= ~SF_Distinct; - } - /* 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 @@ -3869,6 +3915,30 @@ int sqlite3Select( pOrderBy = 0; } + /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and + ** if the select-list is the same as the ORDER BY list, then this query + ** can be rewritten as a GROUP BY. In other words, this: + ** + ** SELECT DISTINCT xyz FROM ... ORDER BY xyz + ** + ** is transformed to: + ** + ** SELECT xyz FROM ... GROUP BY xyz + ** + ** The second form is preferred as a single index (or temp-table) may be + ** used for both the ORDER BY and DISTINCT processing. As originally + ** written the query must use a temp-table for at least one of the ORDER + ** BY and DISTINCT, and an index or separate temp-table for the other. + */ + if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct + && sqlite3ExprListCompare(pOrderBy, p->pEList)==0 + ){ + p->selFlags &= ~SF_Distinct; + p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); + pGroupBy = p->pGroupBy; + 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 @@ -3899,27 +3969,30 @@ int sqlite3Select( iEnd = sqlite3VdbeMakeLabel(v); p->nSelectRow = (double)LARGEST_INT64; computeLimitRegisters(pParse, p, iEnd); + if( p->iLimit==0 && addrSortIndex>=0 ){ + sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen; + p->selFlags |= SF_UseSorter; + } /* Open a virtual index to use for the distinct set. */ if( p->selFlags & SF_Distinct ){ KeyInfo *pKeyInfo; - assert( isAgg || pGroupBy ); distinct = pParse->nTab++; pKeyInfo = keyInfoFromExprList(pParse, p->pEList); - sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0, - (char*)pKeyInfo, P4_KEYINFO_HANDOFF); + addrDistinctIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0, + (char*)pKeyInfo, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); }else{ - distinct = -1; + distinct = addrDistinctIndex = -1; } /* Aggregate and non-aggregate queries are handled differently */ if( !isAgg && pGroupBy==0 ){ - /* This case is for non-aggregate queries - ** Begin the database scan - */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0); + ExprList *pDist = (isDistinct ? p->pEList : 0); + + /* Begin the database scan. */ + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0); if( pWInfo==0 ) goto select_end; if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut; @@ -3928,14 +4001,56 @@ int sqlite3Select( ** into an OP_Noop. */ if( addrSortIndex>=0 && pOrderBy==0 ){ - sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); + sqlite3VdbeChangeToNoop(v, addrSortIndex); p->addrOpenEphm[2] = -1; } - /* Use the standard inner loop - */ - assert(!isDistinct); - selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, -1, pDest, + if( pWInfo->eDistinct ){ + VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ + + assert( addrDistinctIndex>=0 ); + pOp = sqlite3VdbeGetOp(v, addrDistinctIndex); + + assert( isDistinct ); + assert( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED + || pWInfo->eDistinct==WHERE_DISTINCT_UNIQUE + ); + distinct = -1; + if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED ){ + int iJump; + int iExpr; + int iFlag = ++pParse->nMem; + int iBase = pParse->nMem+1; + int iBase2 = iBase + pEList->nExpr; + pParse->nMem += (pEList->nExpr*2); + + /* Change the OP_OpenEphemeral coded earlier to an OP_Integer. The + ** OP_Integer initializes the "first row" flag. */ + pOp->opcode = OP_Integer; + pOp->p1 = 1; + pOp->p2 = iFlag; + + sqlite3ExprCodeExprList(pParse, pEList, iBase, 1); + iJump = sqlite3VdbeCurrentAddr(v) + 1 + pEList->nExpr + 1 + 1; + sqlite3VdbeAddOp2(v, OP_If, iFlag, iJump-1); + for(iExpr=0; iExprnExpr; iExpr++){ + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[iExpr].pExpr); + sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr); + sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iContinue); + + sqlite3VdbeAddOp2(v, OP_Integer, 0, iFlag); + assert( sqlite3VdbeCurrentAddr(v)==iJump ); + sqlite3VdbeAddOp3(v, OP_Move, iBase, iBase2, pEList->nExpr); + }else{ + pOp->opcode = OP_Noop; + } + } + + /* Use the standard inner loop. */ + selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, pDest, pWInfo->iContinue, pWInfo->iBreak); /* End the database scan loop. @@ -3952,6 +4067,8 @@ int sqlite3Select( int iAbortFlag; /* Mem address which causes query abort if positive */ int groupBySort; /* Rows come from source in GROUP BY order */ int addrEnd; /* End of processing for this SELECT */ + int sortPTab = 0; /* Pseudotable used to decode sorting results */ + int sortOut = 0; /* Output register from the sorter */ /* Remove any and all aliases between the result set and the ** GROUP BY clause. @@ -4013,12 +4130,12 @@ int sqlite3Select( /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out - ** that we do not need it after all, the OpenEphemeral instruction + ** that we do not need it after all, the OP_SorterOpen instruction ** will be converted into a Noop. */ sAggInfo.sortingIdx = pParse->nTab++; pKeyInfo = keyInfoFromExprList(pParse, pGroupBy); - addrSortingIdx = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO_HANDOFF); @@ -4045,7 +4162,7 @@ int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0); if( pWInfo==0 ) goto select_end; if( pGroupBy==0 ){ /* The optimizer is able to deliver rows in group by order so @@ -4099,11 +4216,14 @@ int sqlite3Select( } regRecord = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); - sqlite3VdbeAddOp2(v, OP_IdxInsert, sAggInfo.sortingIdx, regRecord); + sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); sqlite3WhereEnd(pWInfo); - sqlite3VdbeAddOp2(v, OP_Sort, sAggInfo.sortingIdx, addrEnd); + sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++; + sortOut = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); + sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); sAggInfo.useSortingIdx = 1; sqlite3ExprCacheClear(pParse); @@ -4116,9 +4236,13 @@ int sqlite3Select( */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3ExprCacheClear(pParse); + if( groupBySort ){ + sqlite3VdbeAddOp2(v, OP_SorterData, sAggInfo.sortingIdx, sortOut); + } for(j=0; jnExpr; j++){ if( groupBySort ){ - sqlite3VdbeAddOp3(v, OP_Column, sAggInfo.sortingIdx, j, iBMem+j); + sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); + if( j==0 ) sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); }else{ sAggInfo.directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); @@ -4157,10 +4281,10 @@ int sqlite3Select( /* End of the loop */ if( groupBySort ){ - sqlite3VdbeAddOp2(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop); + sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop); }else{ sqlite3WhereEnd(pWInfo); - sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1); + sqlite3VdbeChangeToNoop(v, addrSortingIdx); } /* Output the final row of result @@ -4307,7 +4431,7 @@ int sqlite3Select( ** of output. */ resetAccumulator(pParse, &sAggInfo); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, 0, flag); if( pWInfo==0 ){ sqlite3ExprListDelete(db, pDel); goto select_end; diff --git a/src/shell.c b/src/shell.c index a54c922e..07623e52 100644 --- a/src/shell.c +++ b/src/shell.c @@ -12,11 +12,22 @@ ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. */ -#if defined(_WIN32) || defined(WIN32) +#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) /* This needs to come before any includes for MSVC compiler */ #define _CRT_SECURE_NO_WARNINGS #endif +/* +** Enable large-file support for fopen() and friends on unix. +*/ +#ifndef SQLITE_DISABLE_LFS +# define _LARGE_FILE 1 +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# define _LARGEFILE_SOURCE 1 +#endif + #include #include #include @@ -60,7 +71,7 @@ #else /* Make sure isatty() has a prototype. */ -extern int isatty(); +extern int isatty(int); #endif #if defined(_WIN32_WCE) @@ -74,6 +85,11 @@ extern int isatty(); /* True if the timer is enabled */ static int enableTimer = 0; +/* ctype macros that work with signed characters */ +#define IsSpace(X) isspace((unsigned char)X) +#define IsDigit(X) isdigit((unsigned char)X) +#define ToLower(X) (char)tolower((unsigned char)X) + #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL) #include #include @@ -265,23 +281,23 @@ static void iotracePrintf(const char *zFormat, ...){ */ static int isNumber(const char *z, int *realnum){ if( *z=='-' || *z=='+' ) z++; - if( !isdigit(*z) ){ + if( !IsDigit(*z) ){ return 0; } z++; if( realnum ) *realnum = 0; - while( isdigit(*z) ){ z++; } + while( IsDigit(*z) ){ z++; } if( *z=='.' ){ z++; - if( !isdigit(*z) ) return 0; - while( isdigit(*z) ){ z++; } + if( !IsDigit(*z) ) return 0; + while( IsDigit(*z) ){ z++; } if( realnum ) *realnum = 1; } if( *z=='e' || *z=='E' ){ z++; if( *z=='+' || *z=='-' ) z++; - if( !isdigit(*z) ) return 0; - while( isdigit(*z) ){ z++; } + if( !IsDigit(*z) ) return 0; + while( IsDigit(*z) ){ z++; } if( realnum ) *realnum = 1; } return *z==0; @@ -322,7 +338,6 @@ static char *local_getline(char *zPrompt, FILE *in){ char *zLine; int nLine; int n; - int eol; if( zPrompt && *zPrompt ){ printf("%s",zPrompt); @@ -332,8 +347,7 @@ static char *local_getline(char *zPrompt, FILE *in){ zLine = malloc( nLine ); if( zLine==0 ) return 0; n = 0; - eol = 0; - while( !eol ){ + while( 1 ){ if( n+100>nLine ){ nLine = nLine*2 + 100; zLine = realloc(zLine, nLine); @@ -345,7 +359,6 @@ static char *local_getline(char *zPrompt, FILE *in){ return 0; } zLine[n] = 0; - eol = 1; break; } while( zLine[n] ){ n++; } @@ -353,7 +366,7 @@ static char *local_getline(char *zPrompt, FILE *in){ n--; if( n>0 && zLine[n-1]=='\r' ) n--; zLine[n] = 0; - eol = 1; + break; } } zLine = realloc( zLine, n+1 ); @@ -402,6 +415,7 @@ struct callback_data { int statsOn; /* True to display memory stats before each finalize */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ + int nErr; /* Number of errors seen */ int mode; /* An output mode setting */ int writableSchema; /* True if PRAGMA writable_schema=ON */ int showHeader; /* True to show column names in List or Column mode */ @@ -927,27 +941,33 @@ static char *appendText(char *zIn, char const *zAppend, char quote){ ** querying the SQLITE_MASTER table. */ static int run_table_dump_query( - FILE *out, /* Send output here */ - sqlite3 *db, /* Database to query */ - const char *zSelect, /* SELECT statement to extract content */ - const char *zFirstRow /* Print before first row, if not NULL */ + struct callback_data *p, /* Query context */ + const char *zSelect, /* SELECT statement to extract content */ + const char *zFirstRow /* Print before first row, if not NULL */ ){ sqlite3_stmt *pSelect; int rc; - rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0); + rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0); if( rc!=SQLITE_OK || !pSelect ){ + fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); + p->nErr++; return rc; } rc = sqlite3_step(pSelect); while( rc==SQLITE_ROW ){ if( zFirstRow ){ - fprintf(out, "%s", zFirstRow); + fprintf(p->out, "%s", zFirstRow); zFirstRow = 0; } - fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0)); + fprintf(p->out, "%s;\n", sqlite3_column_text(pSelect, 0)); rc = sqlite3_step(pSelect); } - return sqlite3_finalize(pSelect); + rc = sqlite3_finalize(pSelect); + if( rc!=SQLITE_OK ){ + fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); + p->nErr++; + } + return rc; } /* @@ -1029,7 +1049,12 @@ static int display_stats( fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); + fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); + fprintf(pArg->out, "Page cache hits: %d\n", iCur); + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); + fprintf(pArg->out, "Page cache misses: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur); @@ -1069,6 +1094,7 @@ static int shell_exec( ){ sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ int rc = SQLITE_OK; /* Return Code */ + int rc2; const char *zLeftover; /* Tail of unprocessed SQL */ if( pzErrMsg ){ @@ -1085,7 +1111,7 @@ static int shell_exec( if( !pStmt ){ /* this happens for a comment or white-space */ zSql = zLeftover; - while( isspace(zSql[0]) ) zSql++; + while( IsSpace(zSql[0]) ) zSql++; continue; } @@ -1162,10 +1188,11 @@ static int shell_exec( /* Finalize the statement just executed. If this fails, save a ** copy of the error message. Otherwise, set zSql to point to the ** next statement to execute. */ - rc = sqlite3_finalize(pStmt); + rc2 = sqlite3_finalize(pStmt); + if( rc!=SQLITE_NOMEM ) rc = rc2; if( rc==SQLITE_OK ){ zSql = zLeftover; - while( isspace(zSql[0]) ) zSql++; + while( IsSpace(zSql[0]) ) zSql++; }else if( pzErrMsg ){ *pzErrMsg = save_err_msg(db); } @@ -1268,10 +1295,10 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ zSelect = appendText(zSelect, "|| ')' FROM ", 0); zSelect = appendText(zSelect, zTable, '"'); - rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt); + rc = run_table_dump_query(p, zSelect, zPrepStmt); if( rc==SQLITE_CORRUPT ){ zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); - rc = run_table_dump_query(p->out, p->db, zSelect, 0); + run_table_dump_query(p, zSelect, 0); } if( zSelect ) free(zSelect); } @@ -1287,19 +1314,30 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ */ static int run_schema_dump_query( struct callback_data *p, - const char *zQuery, - char **pzErrMsg + const char *zQuery ){ int rc; - rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg); + char *zErr = 0; + rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); if( rc==SQLITE_CORRUPT ){ char *zQ2; int len = strlen30(zQuery); - if( pzErrMsg ) sqlite3_free(*pzErrMsg); + fprintf(p->out, "/****** CORRUPTION ERROR *******/\n"); + if( zErr ){ + fprintf(p->out, "/****** %s ******/\n", zErr); + sqlite3_free(zErr); + zErr = 0; + } zQ2 = malloc( len+100 ); if( zQ2==0 ) return rc; sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery); - rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg); + rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); + if( rc ){ + fprintf(p->out, "/****** ERROR: %s ******/\n", zErr); + }else{ + rc = SQLITE_CORRUPT; + } + sqlite3_free(zErr); free(zQ2); } return rc; @@ -1436,7 +1474,7 @@ static int booleanValue(char *zArg){ int val = atoi(zArg); int j; for(j=0; zArg[j]; j++){ - zArg[j] = (char)tolower(zArg[j]); + zArg[j] = ToLower(zArg[j]); } if( strcmp(zArg,"on")==0 ){ val = 1; @@ -1462,7 +1500,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ /* Parse the input line into tokens. */ while( zLine[i] && nArgout, "PRAGMA foreign_keys=OFF;\n"); fprintf(p->out, "BEGIN TRANSACTION;\n"); p->writableSchema = 0; - sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0); + sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); + p->nErr = 0; if( nArg==1 ){ run_schema_dump_query(p, "SELECT name, type, sql FROM sqlite_master " - "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0 + "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'" ); run_schema_dump_query(p, "SELECT name, type, sql FROM sqlite_master " - "WHERE name=='sqlite_sequence'", 0 + "WHERE name=='sqlite_sequence'" ); - run_table_dump_query(p->out, p->db, + run_table_dump_query(p, "SELECT sql FROM sqlite_master " "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 ); @@ -1574,8 +1612,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){ run_schema_dump_query(p, "SELECT name, type, sql FROM sqlite_master " "WHERE tbl_name LIKE shellstatic() AND type=='table'" - " AND sql NOT NULL", 0); - run_table_dump_query(p->out, p->db, + " AND sql NOT NULL"); + run_table_dump_query(p, "SELECT sql FROM sqlite_master " "WHERE sql NOT NULL" " AND type IN ('index','trigger','view')" @@ -1588,13 +1626,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){ fprintf(p->out, "PRAGMA writable_schema=OFF;\n"); p->writableSchema = 0; } - sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0); - if( zErrMsg ){ - fprintf(stderr,"Error: %s\n", zErrMsg); - sqlite3_free(zErrMsg); - }else{ - fprintf(p->out, "COMMIT;\n"); - } + sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); + sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); + fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); }else if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ @@ -1673,7 +1707,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ fprintf(stderr, "Error: non-null separator required for import\n"); return 1; } - zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); + zSql = sqlite3_mprintf("SELECT * FROM %s", zTable); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); return 1; @@ -1695,7 +1729,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ fprintf(stderr, "Error: out of memory\n"); return 1; } - sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable); + sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zTable); j = strlen30(zSql); for(i=1; i1 ){ int i; - for(i=0; azArg[1][i]; i++) azArg[1][i] = (char)tolower(azArg[1][i]); + for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]); if( strcmp(azArg[1],"sqlite_master")==0 ){ char *new_argv[2], *new_colv[2]; new_argv[0] = "CREATE TABLE sqlite_master (\n" @@ -2202,7 +2235,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( testctrl<0 ){ testctrl = aCtrl[i].ctrlCode; }else{ - fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]); + fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]); testctrl = -1; break; } @@ -2339,7 +2372,7 @@ static int _contains_semicolon(const char *z, int N){ */ static int _all_whitespace(const char *z){ for(; *z; z++){ - if( isspace(*(unsigned char*)z) ) continue; + if( IsSpace(z[0]) ) continue; if( *z=='/' && z[1]=='*' ){ z += 2; while( *z && (*z!='*' || z[1]!='/') ){ z++; } @@ -2364,11 +2397,11 @@ static int _all_whitespace(const char *z){ ** as is the Oracle "/". */ static int _is_command_terminator(const char *zLine){ - while( isspace(*(unsigned char*)zLine) ){ zLine++; }; + while( IsSpace(zLine[0]) ){ zLine++; }; if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){ return 1; /* Oracle */ } - if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o' + if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' && _all_whitespace(&zLine[2]) ){ return 1; /* SQL Server */ } @@ -2438,7 +2471,7 @@ static int process_input(struct callback_data *p, FILE *in){ nSqlPrior = nSql; if( zSql==0 ){ int i; - for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){} + for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} if( zLine[i]!=0 ){ nSql = strlen30(zLine); zSql = malloc( nSql+3 ); @@ -2632,6 +2665,9 @@ static const char zOptions[] = #ifdef SQLITE_ENABLE_VFSTRACE " -vfstrace enable tracing of all VFS calls\n" #endif +#ifdef SQLITE_ENABLE_MULTIPLEX + " -multiplex enable the multiplexor VFS\n" +#endif ; static void usage(int showDetail){ fprintf(stderr, @@ -2707,6 +2743,7 @@ int main(int argc, char **argv){ }else if( strcmp(argv[i],"-batch")==0 ){ stdin_is_interactive = 0; }else if( strcmp(argv[i],"-heap")==0 ){ +#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) int j, c; const char *zSize; sqlite3_int64 szHeap; @@ -2719,7 +2756,6 @@ int main(int argc, char **argv){ if( c=='G' ){ szHeap *= 1000000000; break; } } if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; -#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #endif #ifdef SQLITE_ENABLE_VFSTRACE @@ -2732,6 +2768,11 @@ int main(int argc, char **argv){ int makeDefault ); vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); +#endif +#ifdef SQLITE_ENABLE_MULTIPLEX + }else if( strcmp(argv[i],"-multiplex")==0 ){ + extern int sqlite3_multiple_initialize(const char*,int); + sqlite3_multiplex_initialize(0, 1); #endif }else if( strcmp(argv[i],"-vfs")==0 ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]); @@ -2851,8 +2892,14 @@ int main(int argc, char **argv){ i++; }else if( strcmp(z,"-vfs")==0 ){ i++; +#ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ i++; +#endif +#ifdef SQLITE_ENABLE_MULTIPLEX + }else if( strcmp(z,"-multiplex")==0 ){ + i++; +#endif }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){ usage(1); }else{ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 2e6ca2b7..ed183307 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -736,6 +736,41 @@ struct sqlite3_io_methods { ** Applications should not call [sqlite3_file_control()] with this ** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. +** +** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic +** retry counts and intervals for certain disk I/O operations for the +** windows [VFS] in order to work to provide robustness against +** anti-virus programs. By default, the windows VFS will retry file read, +** file write, and file delete operations up to 10 times, with a delay +** of 25 milliseconds before the first retry and with the delay increasing +** by an additional 25 milliseconds with each subsequent retry. This +** opcode allows those to values (10 retries and 25 milliseconds of delay) +** to be adjusted. The values are changed for all database connections +** within the same process. The argument is a pointer to an array of two +** integers where the first integer i the new retry count and the second +** integer is the delay. If either integer is negative, then the setting +** is not changed but instead the prior value of that setting is written +** into the array entry, allowing the current retry settings to be +** interrogated. The zDbName parameter is ignored. +** +** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the +** persistent [WAL | Write AHead Log] setting. By default, the auxiliary +** write ahead log and shared memory files used for transaction control +** are automatically deleted when the latest connection to the database +** closes. Setting persistent WAL mode causes those files to persist after +** close. Persisting the files is useful when other processes that do not +** have write permission on the directory containing the database file want +** to read the database file, as the WAL and shared memory files must exist +** in order for the database to be readable. The fourth parameter to +** [sqlite3_file_control()] for this opcode should be a pointer to an integer. +** That integer is 0 to disable persistent WAL mode or 1 to enable persistent +** WAL mode. If the integer is -1, then it is overwritten with the current +** WAL persistence setting. +** +** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening +** a write transaction to indicate that, unless it is rolled back for some +** reason, the entire database file will be overwritten by the current +** transaction. This is used by VACUUM operations. */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 @@ -745,7 +780,9 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 - +#define SQLITE_FCNTL_WIN32_AV_RETRY 9 +#define SQLITE_FCNTL_PERSIST_WAL 10 +#define SQLITE_FCNTL_OVERWRITE 11 /* ** CAPI3REF: Mutex Handle @@ -1173,16 +1210,10 @@ int sqlite3_db_config(sqlite3*, int op, ...); ** order to verify that SQLite recovers gracefully from such ** conditions. ** -** The xMalloc and xFree methods must work like the -** malloc() and free() functions from the standard C library. -** The xRealloc method must work like realloc() from the standard C library -** with the exception that if the second argument to xRealloc is zero, -** xRealloc must be a no-op - it must not perform any allocation or -** deallocation. ^SQLite guarantees that the second argument to +** The xMalloc, xRealloc, and xFree methods must work like the +** malloc(), realloc() and free() functions from the standard C library. +** ^SQLite guarantees that the second argument to ** xRealloc is always a value returned by a prior call to xRoundup. -** And so in cases where xRoundup always returns a positive number, -** xRealloc can perform exactly as the standard library realloc() and -** still be in compliance with this specification. ** ** xSize should return the allocated size of a memory allocation ** previously obtained from xMalloc or xRealloc. The allocated size @@ -1368,8 +1399,8 @@ struct sqlite3_mem_methods { ** allocator is engaged to handle all of SQLites memory allocation needs. ** The first pointer (the memory pointer) must be aligned to an 8-byte ** boundary or subsequent behavior of SQLite will be undefined. -** The minimum allocation size is capped at 2^12. Reasonable values -** for the minimum allocation size are 2^5 through 2^8. +** The minimum allocation size is capped at 2**12. Reasonable values +** for the minimum allocation size are 2**5 through 2**8. ** ** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
**
^(This option takes a single argument which is a pointer to an @@ -2768,7 +2799,8 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** that the supplied string is nul-terminated, then there is a small ** performance advantage to be gained by passing an nByte parameter that ** is equal to the number of bytes in the input string including -** the nul-terminator bytes. +** the nul-terminator bytes as this saves SQLite from having to +** make a copy of the input string. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -2819,7 +2851,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column -** and the [SQLITE_ENABLE_STAT2] compile-time option is enabled. +** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. ** the ** ** @@ -2989,6 +3021,13 @@ typedef struct sqlite3_context sqlite3_context; ** number of bytes in the value, not the number of characters.)^ ** ^If the fourth parameter is negative, the length of the string is ** the number of bytes up to the first zero terminator. +** If a non-negative fourth parameter is provided to sqlite3_bind_text() +** or sqlite3_bind_text16() then that parameter must be the byte offset +** where the NUL terminator would occur assuming the string were NUL +** terminated. If any NUL characters occur at byte offsets less than +** the value of the fourth parameter then the resulting string value will +** contain embedded NULs. The result of expressions involving strings +** with embedded NULs is undefined. ** ** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and ** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or @@ -3322,6 +3361,12 @@ int sqlite3_step(sqlite3_stmt*); ** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of ** interfaces) then sqlite3_data_count(P) returns 0. ** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. +** ^The sqlite3_data_count(P) routine returns 0 if the previous call to +** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) +** will return non-zero if previous call to [sqlite3_step](P) returned +** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] +** where it always returns zero since each step of that multi-step +** pragma returns 0 columns of data. ** ** See also: [sqlite3_column_count()] */ @@ -4001,7 +4046,12 @@ typedef void (*sqlite3_destructor_type)(void*); ** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** is non-negative, then as many bytes (not characters) of the text ** pointed to by the 2nd parameter are taken as the application-defined -** function result. +** function result. If the 3rd parameter is non-negative, then it +** must be the byte offset into the string where the NUL terminator would +** appear if the string where NUL terminated. If any NUL characters occur +** in the string at a byte offset that is less than the value of the 3rd +** parameter, then the resulting string will contain embedded NULs and the +** result of expressions operating on strings with embedded NULs is undefined. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that ** function as the destructor on the text or BLOB result when it has @@ -5784,6 +5834,18 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. **
+** +** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(
SQLITE_DBSTATUS_CACHE_HIT
+**
This parameter returns the number of pager cache hits that have +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT +** is always 0. +**
+** +** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(
SQLITE_DBSTATUS_CACHE_MISS
+**
This parameter returns the number of pager cache misses that have +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS +** is always 0. +**
** */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 @@ -5793,7 +5855,9 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 -#define SQLITE_DBSTATUS_MAX 6 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_CACHE_HIT 7 +#define SQLITE_DBSTATUS_CACHE_MISS 8 +#define SQLITE_DBSTATUS_MAX 8 /* Largest defined DBSTATUS */ /* @@ -5847,7 +5911,6 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** 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. -** ** */ #define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index e45e691f..5abcde2c 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -49,8 +49,10 @@ struct sqlite3_api_routines { int (*busy_timeout)(sqlite3*,int ms); int (*changes)(sqlite3*); int (*close)(sqlite3*); - int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*)); - int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*)); + int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const char*)); + int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const void*)); const void * (*column_blob)(sqlite3_stmt*,int iCol); int (*column_bytes)(sqlite3_stmt*,int iCol); int (*column_bytes16)(sqlite3_stmt*,int iCol); @@ -75,10 +77,18 @@ struct sqlite3_api_routines { void * (*commit_hook)(sqlite3*,int(*)(void*),void*); int (*complete)(const char*sql); int (*complete16)(const void*sql); - int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*)); - int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*)); - int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*)); - int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*)); + int (*create_collation)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_collation16)(sqlite3*,const void*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_function)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_function16)(sqlite3*,const void*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); int (*data_count)(sqlite3_stmt*pStmt); sqlite3 * (*db_handle)(sqlite3_stmt*); @@ -123,16 +133,19 @@ struct sqlite3_api_routines { void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_value)(sqlite3_context*,sqlite3_value*); void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); - int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*); + int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, + const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); char * (*snprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); - int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*); + int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, + char const**,char const**,int*,int*,int*); void (*thread_cleanup)(void); int (*total_changes)(sqlite3*); void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); - void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*); + void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, + sqlite_int64),void*); void * (*user_data)(sqlite3_context*); const void * (*value_blob)(sqlite3_value*); int (*value_bytes)(sqlite3_value*); @@ -154,15 +167,19 @@ struct sqlite3_api_routines { int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); int (*clear_bindings)(sqlite3_stmt*); /* Added by 3.4.1 */ - int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *)); + int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, + void (*xDestroy)(void *)); /* Added by 3.5.0 */ int (*bind_zeroblob)(sqlite3_stmt*,int,int); int (*blob_bytes)(sqlite3_blob*); int (*blob_close)(sqlite3_blob*); - int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**); + int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, + int,sqlite3_blob**); int (*blob_read)(sqlite3_blob*,void*,int,int); int (*blob_write)(sqlite3_blob*,const void*,int,int); - int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*)); + int (*create_collation_v2)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*), + void(*)(void*)); int (*file_control)(sqlite3*,const char*,int,void*); sqlite3_int64 (*memory_highwater)(int); sqlite3_int64 (*memory_used)(void); @@ -198,7 +215,11 @@ struct sqlite3_api_routines { int (*backup_step)(sqlite3_backup*,int); const char *(*compileoption_get)(int); int (*compileoption_used)(const char*); - int (*create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*)); + int (*create_function_v2)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*)); int (*db_config)(sqlite3*,int,...); sqlite3_mutex *(*db_mutex)(sqlite3*); int (*db_status)(sqlite3*,int,int*,int*,int); @@ -212,6 +233,9 @@ struct sqlite3_api_routines { int (*wal_autocheckpoint)(sqlite3*,int); int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); + int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); + int (*vtab_config)(sqlite3*,int op,...); + int (*vtab_on_conflict)(sqlite3*); }; /* @@ -412,6 +436,9 @@ struct sqlite3_api_routines { #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_hook sqlite3_api->wal_hook +#define sqlite3_blob_reopen sqlite3_api->blob_reopen +#define sqlite3_vtab_config sqlite3_api->vtab_config +#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict #endif /* SQLITE_CORE */ #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 09f64b79..9e276541 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -76,13 +76,6 @@ #include #endif -/* -** The number of samples of an index that SQLite takes in order to -** construct a histogram of the table content when running ANALYZE -** and with SQLITE_ENABLE_STAT2 -*/ -#define SQLITE_INDEX_SAMPLES 10 - /* ** The following macros are used to cast pointers to integers and ** integers to pointers. The way you do this varies from one compiler @@ -147,19 +140,25 @@ ** specify which memory allocation subsystem to use. ** ** SQLITE_SYSTEM_MALLOC // Use normal system malloc() +** SQLITE_WIN32_MALLOC // Use Win32 native heap API ** SQLITE_MEMDEBUG // Debugging version of system malloc() ** +** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the +** assert() macro is enabled, each call into the Win32 native heap subsystem +** will cause HeapValidate to be called. If heap validation should fail, an +** assertion will be triggered. +** ** (Historical note: There used to be several other options, but we've -** pared it down to just these two.) +** pared it down to just these three.) ** ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as ** the default. */ -#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)>1 +#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)>1 # error "At most one of the following compile-time configuration options\ - is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG" + is allows: SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG" #endif -#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)==0 +#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)==0 # define SQLITE_SYSTEM_MALLOC 1 #endif @@ -445,6 +444,18 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) +/* +** The datatype used to store estimates of the number of rows in a +** table or index. This is an unsigned integer type. For 99.9% of +** the world, a 32-bit integer is sufficient. But a 64-bit integer +** can be used at compile-time if desired. +*/ +#ifdef SQLITE_64BIT_STATS + typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */ +#else + typedef u32 tRowcnt; /* 32-bit is the default */ +#endif + /* ** Macros to determine whether the machine is big or little endian, ** evaluated at runtime. @@ -956,6 +967,7 @@ struct sqlite3 { #define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */ #define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */ +#define SQLITE_DistinctOpt 0x80 /* DISTINCT using indexes */ #define SQLITE_OptMask 0xff /* Mask of all disablable opts */ /* @@ -1277,7 +1289,7 @@ struct Table { Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ - unsigned nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ + tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u16 nRef; /* Number of pointers to this Table */ u8 tabFlags; /* Mask of TF_* values */ @@ -1476,7 +1488,7 @@ struct Index { char *zName; /* Name of this index */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ - unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ + tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ @@ -1487,20 +1499,29 @@ struct Index { Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ - IndexSample *aSample; /* Array of SQLITE_INDEX_SAMPLES samples */ +#ifdef SQLITE_ENABLE_STAT3 + int nSample; /* Number of elements in aSample[] */ + tRowcnt avgEq; /* Average nEq value for key values not in aSample */ + IndexSample *aSample; /* Samples of the left-most key */ +#endif }; /* -** Each sample stored in the sqlite_stat2 table is represented in memory -** using a structure of this type. +** Each sample stored in the sqlite_stat3 table is represented in memory +** using a structure of this type. See documentation at the top of the +** analyze.c source file for additional information. */ struct IndexSample { union { char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */ - double r; /* Value if eType is SQLITE_FLOAT or SQLITE_INTEGER */ + double r; /* Value if eType is SQLITE_FLOAT */ + i64 i; /* Value if eType is SQLITE_INTEGER */ } u; u8 eType; /* SQLITE_NULL, SQLITE_INTEGER ... etc. */ - u8 nByte; /* Size in byte of text or blob. */ + int nByte; /* Size in byte of text or blob. */ + tRowcnt nEq; /* Est. number of rows where the key equals this sample */ + tRowcnt nLt; /* Est. number of rows where key is less than this sample */ + tRowcnt nDLt; /* Est. number of distinct keys less than this sample */ }; /* @@ -1535,6 +1556,7 @@ struct AggInfo { u8 useSortingIdx; /* In direct mode, reference the sorting index rather ** than the source table */ int sortingIdx; /* Cursor number of the sorting index */ + int sortingIdxPTab; /* Cursor number of pseudo-table */ ExprList *pGroupBy; /* The group by clause */ int nSortingColumn; /* Number of columns in the sorting index */ struct AggInfo_col { /* For each column used in source tables */ @@ -1844,9 +1866,11 @@ struct SrcList { char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ - u8 isPopulated; /* Temporary table associated with SELECT is populated */ + int addrFillSub; /* Address of subroutine to manifest a subquery */ + int regReturn; /* Register holding return address of addrFillSub */ u8 jointype; /* Type of join between this able and the previous */ u8 notIndexed; /* True if there is a NOT INDEXED clause */ + u8 isCorrelated; /* True if sub-query is correlated */ #ifndef SQLITE_OMIT_EXPLAIN u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ #endif @@ -1949,10 +1973,10 @@ 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 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 */ +#define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ +#define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ +#define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ +#define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ /* ** The WHERE clause processing routine has two halves. The @@ -1966,6 +1990,7 @@ struct WhereInfo { u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ + u8 eDistinct; SrcList *pTabList; /* List of tables in the join */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ @@ -1977,6 +2002,9 @@ struct WhereInfo { WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; +#define WHERE_DISTINCT_UNIQUE 1 +#define WHERE_DISTINCT_ORDERED 2 + /* ** A NameContext defines a context in which to resolve table and column ** names. The context consists of a list of tables (the pSrcList) field and @@ -2062,6 +2090,7 @@ struct Select { #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ +#define SF_UseSorter 0x0040 /* Sort using a sorter */ /* @@ -2701,6 +2730,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); #endif void sqlite3DropTable(Parse*, SrcList*, int, int); +void sqlite3CodeDropTable(Parse*, Table*, int, int); void sqlite3DeleteTable(sqlite3*, Table*); #ifndef SQLITE_OMIT_AUTOINCREMENT void sqlite3AutoincrementBegin(Parse *pParse); @@ -2738,7 +2768,7 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); -WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16); +WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16); void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); @@ -2957,7 +2987,7 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void sqlite3ValueFree(sqlite3_value*); sqlite3_value *sqlite3ValueNew(sqlite3 *); char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *); #endif int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); @@ -3059,6 +3089,7 @@ void sqlite3AutoLoadExtensions(sqlite3*); # define sqlite3VtabUnlock(X) # define sqlite3VtabUnlockList(X) # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK +# define sqlite3GetVTable(X,Y) ((VTable*)0) #else void sqlite3VtabClear(sqlite3 *db, Table*); int sqlite3VtabSync(sqlite3 *db, char **); @@ -3068,6 +3099,7 @@ void sqlite3AutoLoadExtensions(sqlite3*); void sqlite3VtabUnlock(VTable *); void sqlite3VtabUnlockList(sqlite3*); int sqlite3VtabSavepoint(sqlite3 *, int, int); + VTable *sqlite3GetVTable(sqlite3*, Table*); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif void sqlite3VtabMakeWritable(Parse*,Table*); @@ -3087,7 +3119,6 @@ int sqlite3Reprepare(Vdbe*); 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, int*, int*); int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); diff --git a/src/status.c b/src/status.c index b8c1d58d..b23238bb 100644 --- a/src/status.c +++ b/src/status.c @@ -218,6 +218,28 @@ int sqlite3_db_status( break; } + /* + ** Set *pCurrent to the total cache hits or misses encountered by all + ** pagers the database handle is connected to. *pHighwater is always set + ** to zero. + */ + case SQLITE_DBSTATUS_CACHE_HIT: + case SQLITE_DBSTATUS_CACHE_MISS: { + int i; + int nRet = 0; + assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); + + for(i=0; inDb; i++){ + if( db->aDb[i].pBt ){ + Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); + sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); + } + } + *pHighwater = 0; + *pCurrent = nRet; + break; + } + default: { rc = SQLITE_ERROR; } diff --git a/src/tclsqlite.c b/src/tclsqlite.c index ad4d27a1..c8f0fbd3 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -107,6 +107,11 @@ typedef struct IncrblobChannel IncrblobChannel; /* ** There is one instance of this structure for each SQLite database ** that has been opened by the SQLite TCL interface. +** +** If this module is built with SQLITE_TEST defined (to create the SQLite +** testfixture executable), then it may be configured to use either +** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements. +** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used. */ typedef struct SqliteDb SqliteDb; struct SqliteDb { @@ -135,6 +140,9 @@ struct SqliteDb { IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ int nStep, nSort, nIndex; /* Statistics for most recent operation */ int nTransaction; /* Number of nested [transaction] methods */ +#ifdef SQLITE_TEST + int bLegacyPrepare; /* True to use sqlite3_prepare() */ +#endif }; struct IncrblobChannel { @@ -429,20 +437,33 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ return pNew; } +/* +** Free a single SqlPreparedStmt object. +*/ +static void dbFreeStmt(SqlPreparedStmt *pStmt){ +#ifdef SQLITE_TEST + if( sqlite3_sql(pStmt->pStmt)==0 ){ + Tcl_Free((char *)pStmt->zSql); + } +#endif + sqlite3_finalize(pStmt->pStmt); + Tcl_Free((char *)pStmt); +} + /* ** Finalize and free a list of prepared statements */ -static void flushStmtCache( SqliteDb *pDb ){ +static void flushStmtCache(SqliteDb *pDb){ SqlPreparedStmt *pPreStmt; + SqlPreparedStmt *pNext; - while( pDb->stmtList ){ - sqlite3_finalize( pDb->stmtList->pStmt ); - pPreStmt = pDb->stmtList; - pDb->stmtList = pDb->stmtList->pNext; - Tcl_Free( (char*)pPreStmt ); + for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){ + pNext = pPreStmt->pNext; + dbFreeStmt(pPreStmt); } pDb->nStmt = 0; pDb->stmtLast = 0; + pDb->stmtList = 0; } /* @@ -898,7 +919,7 @@ static int auth_callback( Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); - zReply = Tcl_GetStringResult(pDb->interp); + zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; if( strcmp(zReply,"SQLITE_OK")==0 ){ rc = SQLITE_OK; }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ @@ -947,14 +968,12 @@ static char *local_getline(char *zPrompt, FILE *in){ char *zLine; int nLine; int n; - int eol; nLine = 100; zLine = malloc( nLine ); if( zLine==0 ) return 0; n = 0; - eol = 0; - while( !eol ){ + while( 1 ){ if( n+100>nLine ){ nLine = nLine*2 + 100; zLine = realloc(zLine, nLine); @@ -966,14 +985,13 @@ static char *local_getline(char *zPrompt, FILE *in){ return 0; } zLine[n] = 0; - eol = 1; break; } while( zLine[n] ){ n++; } if( n>0 && zLine[n-1]=='\n' ){ n--; zLine[n] = 0; - eol = 1; + break; } } zLine = realloc( zLine, n+1 ); @@ -1030,6 +1048,27 @@ static int DbTransPostCmd( return rc; } +/* +** Unless SQLITE_TEST is defined, this function is a simple wrapper around +** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either +** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending +** on whether or not the [db_use_legacy_prepare] command has been used to +** configure the connection. +*/ +static int dbPrepare( + SqliteDb *pDb, /* Database object */ + const char *zSql, /* SQL to compile */ + sqlite3_stmt **ppStmt, /* OUT: Prepared statement */ + const char **pzOut /* OUT: Pointer to next SQL statement */ +){ +#ifdef SQLITE_TEST + if( pDb->bLegacyPrepare ){ + return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut); + } +#endif + return sqlite3_prepare_v2(pDb->db, zSql, -1, ppStmt, pzOut); +} + /* ** Search the cache for a prepared-statement object that implements the ** first SQL statement in the buffer pointed to by parameter zIn. If @@ -1100,7 +1139,7 @@ static int dbPrepareAndBind( if( pPreStmt==0 ){ int nByte; - if( SQLITE_OK!=sqlite3_prepare_v2(pDb->db, zSql, -1, &pStmt, pzOut) ){ + if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); return TCL_ERROR; } @@ -1127,6 +1166,14 @@ static int dbPrepareAndBind( pPreStmt->nSql = (*pzOut - zSql); pPreStmt->zSql = sqlite3_sql(pStmt); pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; +#ifdef SQLITE_TEST + if( pPreStmt->zSql==0 ){ + char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1); + memcpy(zCopy, zSql, pPreStmt->nSql); + zCopy[pPreStmt->nSql] = '\0'; + pPreStmt->zSql = zCopy; + } +#endif } assert( pPreStmt ); assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); @@ -1180,7 +1227,6 @@ static int dbPrepareAndBind( return TCL_OK; } - /* ** Release a statement reference obtained by calling dbPrepareAndBind(). ** There should be exactly one call to this function for each call to @@ -1205,8 +1251,7 @@ static void dbReleaseStmt( if( pDb->maxStmt<=0 || discard ){ /* If the cache is turned off, deallocated the statement */ - sqlite3_finalize(pPreStmt->pStmt); - Tcl_Free((char *)pPreStmt); + dbFreeStmt(pPreStmt); }else{ /* Add the prepared statement to the beginning of the cache list. */ pPreStmt->pNext = pDb->stmtList; @@ -1226,11 +1271,11 @@ static void dbReleaseStmt( /* If we have too many statement in cache, remove the surplus from ** the end of the cache list. */ while( pDb->nStmt>pDb->maxStmt ){ - sqlite3_finalize(pDb->stmtLast->pStmt); - pDb->stmtLast = pDb->stmtLast->pPrev; - Tcl_Free((char*)pDb->stmtLast->pNext); + SqlPreparedStmt *pLast = pDb->stmtLast; + pDb->stmtLast = pLast->pPrev; pDb->stmtLast->pNext = 0; pDb->nStmt--; + dbFreeStmt(pLast); } } } @@ -1363,9 +1408,12 @@ static void dbEvalRowInfo( ** no further rows available. This is similar to SQLITE_DONE. */ static int dbEvalStep(DbEvalContext *p){ + const char *zPrevSql = 0; /* Previous value of p->zSql */ + while( p->zSql[0] || p->pPreStmt ){ int rc; if( p->pPreStmt==0 ){ + zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql); rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); if( rc!=TCL_OK ) return rc; }else{ @@ -1392,8 +1440,19 @@ static int dbEvalStep(DbEvalContext *p){ if( rcs!=SQLITE_OK ){ /* If a run-time error occurs, report the error and stop reading ** the SQL. */ - Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db))); dbReleaseStmt(pDb, pPreStmt, 1); +#if SQLITE_TEST + if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ + /* If the runtime error was an SQLITE_SCHEMA, and the database + ** handle is configured to use the legacy sqlite3_prepare() + ** interface, retry prepare()/step() on the same SQL statement. + ** This only happens once. If there is a second SQLITE_SCHEMA + ** error, the error will be returned to the caller. */ + p->zSql = zPrevSql; + continue; + } +#endif + Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db))); return TCL_ERROR; }else{ dbReleaseStmt(pDb, pPreStmt, 0); @@ -2059,7 +2118,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ zCommit = "COMMIT"; while( (zLine = local_getline(0, in))!=0 ){ char *z; - i = 0; lineno++; azCol[0] = zLine; for(i=0, z=zLine; *z; z++){ @@ -2180,6 +2238,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ if( choice==DB_ONECOLUMN ){ if( rc==TCL_OK ){ Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0)); + }else if( rc==TCL_BREAK ){ + Tcl_ResetResult(interp); } }else if( rc==TCL_BREAK || rc==TCL_OK ){ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc==TCL_OK)); @@ -2486,14 +2546,16 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ ** Change the encryption key on the currently open database. */ case DB_REKEY: { +#ifdef SQLITE_HAS_CODEC int nKey; void *pKey; +#endif if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "KEY"); return TCL_ERROR; } - pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); #ifdef SQLITE_HAS_CODEC + pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); rc = sqlite3_rekey(pDb->db, pKey, nKey); if( rc ){ Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); @@ -2856,8 +2918,6 @@ static int DbObjCmdAdaptor( */ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ SqliteDb *p; - void *pKey = 0; - int nKey = 0; const char *zArg; char *zErrMsg; int i; @@ -2865,6 +2925,10 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ const char *zVfs = 0; int flags; Tcl_DString translatedFilename; +#ifdef SQLITE_HAS_CODEC + void *pKey = 0; + int nKey = 0; +#endif /* In normal use, each TCL interpreter runs in a single thread. So ** by default, we can turn of mutexing on SQLite database connections. @@ -2896,7 +2960,9 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ for(i=3; i+1 \"\n" - "} else {\n" - "puts -nonewline \"% \"\n" - "}\n" - "flush stdout\n" - "append line [gets stdin]\n" - "if {[info complete $line]} {\n" - "if {[catch {uplevel #0 $line} result]} {\n" - "puts stderr \"Error: $result\"\n" - "} elseif {$result!=\"\"} {\n" - "puts $result\n" +static const char *tclsh_main_loop(void){ + static const char zMainloop[] = + "set line {}\n" + "while {![eof stdin]} {\n" + "if {$line!=\"\"} {\n" + "puts -nonewline \"> \"\n" + "} else {\n" + "puts -nonewline \"% \"\n" + "}\n" + "flush stdout\n" + "append line [gets stdin]\n" + "if {[info complete $line]} {\n" + "if {[catch {uplevel #0 $line} result]} {\n" + "puts stderr \"Error: $result\"\n" + "} elseif {$result!=\"\"} {\n" + "puts $result\n" + "}\n" + "set line {}\n" + "} else {\n" + "append line \\n\n" "}\n" - "set line {}\n" - "} else {\n" - "append line \\n\n" "}\n" - "}\n" -; + ; + return zMainloop; +} #endif #if TCLSH==2 -static char zMainloop[] = -#include "spaceanal_tcl.h" -; +static const char *tclsh_main_loop(void); #endif #ifdef SQLITE_TEST @@ -3527,6 +3594,44 @@ static int init_all_cmd( init_all(slave); return TCL_OK; } + +/* +** Tclcmd: db_use_legacy_prepare DB BOOLEAN +** +** The first argument to this command must be a database command created by +** [sqlite3]. If the second argument is true, then the handle is configured +** to use the sqlite3_prepare_v2() function to prepare statements. If it +** is false, sqlite3_prepare(). +*/ +static int db_use_legacy_prepare_cmd( + ClientData cd, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + Tcl_CmdInfo cmdInfo; + SqliteDb *pDb; + int bPrepare; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN"); + return TCL_ERROR; + } + + if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ + Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0); + return TCL_ERROR; + } + pDb = (SqliteDb*)cmdInfo.objClientData; + if( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){ + return TCL_ERROR; + } + + pDb->bLegacyPrepare = bPrepare; + + Tcl_ResetResult(interp); + return TCL_OK; +} #endif /* @@ -3547,6 +3652,17 @@ static void init_all(Tcl_Interp *interp){ Md5_Init(interp); #endif + /* Install the [register_dbstat_vtab] command to access the implementation + ** of virtual table dbstat (source file test_stat.c). This command is + ** required for testfixture and sqlite3_analyzer, but not by the production + ** Tcl extension. */ +#if defined(SQLITE_TEST) || TCLSH==2 + { + extern int SqlitetestStat_Init(Tcl_Interp*); + SqlitetestStat_Init(interp); + } +#endif + #ifdef SQLITE_TEST { extern int Sqliteconfig_Init(Tcl_Interp*); @@ -3576,7 +3692,6 @@ static void init_all(Tcl_Interp *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*); extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*); @@ -3620,7 +3735,6 @@ static void init_all(Tcl_Interp *interp){ Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); - SqlitetestStat_Init(interp); Sqlitetestrtree_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); @@ -3633,7 +3747,12 @@ static void init_all(Tcl_Interp *interp){ Sqlitetestfts3_Init(interp); #endif - Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0); + Tcl_CreateObjCommand( + interp, "load_testfixture_extensions", init_all_cmd, 0, 0 + ); + Tcl_CreateObjCommand( + interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 + ); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); @@ -3651,12 +3770,13 @@ int TCLSH_MAIN(int argc, char **argv){ ** sqlite3_initialize() is. */ sqlite3_shutdown(); + Tcl_FindExecutable(argv[0]); + interp = Tcl_CreateInterp(); + #if TCLSH==2 sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); #endif - Tcl_FindExecutable(argv[0]); - interp = Tcl_CreateInterp(); init_all(interp); if( argc>=2 ){ int i; @@ -3677,7 +3797,7 @@ int TCLSH_MAIN(int argc, char **argv){ } } if( TCLSH==2 || argc<=1 ){ - Tcl_GlobalEval(interp, zMainloop); + Tcl_GlobalEval(interp, tclsh_main_loop()); } return 0; } diff --git a/src/test1.c b/src/test1.c index 7fdf54b1..26342522 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4395,7 +4395,7 @@ static u8 *sqlite3_stack_baseline = 0; static void prepStack(void){ int i; u32 bigBuf[65536]; - for(i=0; ievName ){ + HANDLE ev = OpenEvent(EVENT_MODIFY_STATE, FALSE, p->evName); + if ( ev ){ + SetEvent(ev); + CloseHandle(ev); + } + } + if( p->delay1 ) Sleep(p->delay1); + if( LockFile(p->h, 0, 0, 100000000, 0) ){ + Sleep(p->delay2); + UnlockFile(p->h, 0, 0, 100000000, 0); + p->ok = 1; + }else{ + p->err = 1; + } + CloseHandle(p->h); + p->h = 0; + p->delay1 = 0; + p->delay2 = 0; +} +#endif + +#if SQLITE_OS_WIN +/* +** lock_win32_file FILENAME DELAY1 DELAY2 +** +** Get an exclusive manditory lock on file for DELAY2 milliseconds. +** Wait DELAY1 milliseconds before acquiring the lock. +*/ +static int win32_file_lock( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + static struct win32FileLocker x = { "win32_file_lock", 0, 0, 0, 0, 0 }; + const char *zFilename; + char zBuf[200]; + int retry = 0; + HANDLE ev; + DWORD wResult; + + if( objc!=4 && objc!=1 ){ + Tcl_WrongNumArgs(interp, 1, objv, "FILENAME DELAY1 DELAY2"); + return TCL_ERROR; + } + if( objc==1 ){ + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d", + x.ok, x.err, x.delay1, x.delay2, x.h); + Tcl_AppendResult(interp, zBuf, (char*)0); + return TCL_OK; + } + while( x.h && retry<30 ){ + retry++; + Sleep(100); + } + if( x.h ){ + Tcl_AppendResult(interp, "busy", (char*)0); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[2], &x.delay1) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &x.delay2) ) return TCL_ERROR; + zFilename = Tcl_GetString(objv[1]); + x.h = CreateFile(zFilename, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + if( !x.h ){ + Tcl_AppendResult(interp, "cannot open file: ", zFilename, (char*)0); + return TCL_ERROR; + } + ev = CreateEvent(NULL, TRUE, FALSE, x.evName); + if ( !ev ){ + Tcl_AppendResult(interp, "cannot create event: ", x.evName, (char*)0); + return TCL_ERROR; + } + _beginthread(win32_file_locker, 0, (void*)&x); + Sleep(0); + if ( (wResult = WaitForSingleObject(ev, 10000))!=WAIT_OBJECT_0 ){ + sqlite3_snprintf(sizeof(zBuf), zBuf, "0x%x", wResult); + Tcl_AppendResult(interp, "wait failed: ", zBuf, (char*)0); + CloseHandle(ev); + return TCL_ERROR; + } + CloseHandle(ev); + return TCL_OK; +} +#endif + /* ** optimization_control DB OPT BOOLEAN @@ -5754,6 +5928,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "restore_prng_state", restore_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 }, { "optimization_control", optimization_control,0}, +#if SQLITE_OS_WIN + { "lock_win32_file", win32_file_lock, 0 }, +#endif { "tcl_objproc", runAsObjProc, 0 }, /* sqlite3_column_*() API */ @@ -5802,7 +5979,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "file_control_lasterrno_test", file_control_lasterrno_test, 0 }, { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, { "file_control_chunksize_test", file_control_chunksize_test, 0 }, - { "file_control_sizehint_test", file_control_sizehint_test, 0 }, + { "file_control_sizehint_test", file_control_sizehint_test, 0 }, + { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, + { "file_control_persist_wal", file_control_persist_wal, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, diff --git a/src/test6.c b/src/test6.c index c9c8a4d2..23fb14c5 100644 --- a/src/test6.c +++ b/src/test6.c @@ -505,6 +505,16 @@ static int cfCheckReservedLock(sqlite3_file *pFile, int *pResOut){ return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile, pResOut); } static int cfFileControl(sqlite3_file *pFile, int op, void *pArg){ + if( op==SQLITE_FCNTL_SIZE_HINT ){ + CrashFile *pCrash = (CrashFile *)pFile; + i64 nByte = *(i64 *)pArg; + if( nByte>pCrash->iSize ){ + if( SQLITE_OK==writeListAppend(pFile, nByte, 0, 0) ){ + pCrash->iSize = nByte; + } + } + return SQLITE_OK; + } return sqlite3OsFileControl(((CrashFile *)pFile)->pRealFile, op, pArg); } diff --git a/src/test8.c b/src/test8.c index b3e6058a..283d790b 100644 --- a/src/test8.c +++ b/src/test8.c @@ -1232,12 +1232,50 @@ static int echoRename(sqlite3_vtab *vtab, const char *zNewName){ return rc; } +static int echoSavepoint(sqlite3_vtab *pVTab, int iSavepoint){ + assert( pVTab ); + return SQLITE_OK; +} + +static int echoRelease(sqlite3_vtab *pVTab, int iSavepoint){ + assert( pVTab ); + return SQLITE_OK; +} + +static int echoRollbackTo(sqlite3_vtab *pVTab, int iSavepoint){ + assert( pVTab ); + return SQLITE_OK; +} + /* ** A virtual table module that merely "echos" the contents of another ** table (like an SQL VIEW). */ static sqlite3_module echoModule = { - 0, /* iVersion */ + 1, /* iVersion */ + echoCreate, + echoConnect, + echoBestIndex, + echoDisconnect, + echoDestroy, + echoOpen, /* xOpen - open a cursor */ + echoClose, /* xClose - close a cursor */ + echoFilter, /* xFilter - configure scan constraints */ + echoNext, /* xNext - advance a cursor */ + echoEof, /* xEof */ + echoColumn, /* xColumn - read data */ + echoRowid, /* xRowid - read data */ + echoUpdate, /* xUpdate - write data */ + echoBegin, /* xBegin - begin transaction */ + echoSync, /* xSync - sync transaction */ + echoCommit, /* xCommit - commit transaction */ + echoRollback, /* xRollback - rollback transaction */ + echoFindFunction, /* xFindFunction - function overloading */ + echoRename /* xRename - rename the table */ +}; + +static sqlite3_module echoModuleV2 = { + 2, /* iVersion */ echoCreate, echoConnect, echoBestIndex, @@ -1257,6 +1295,9 @@ static sqlite3_module echoModule = { echoRollback, /* xRollback - rollback transaction */ echoFindFunction, /* xFindFunction - function overloading */ echoRename, /* xRename - rename the table */ + echoSavepoint, + echoRelease, + echoRollbackTo }; /* @@ -1284,9 +1325,18 @@ static int register_echo_module( return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + + /* Virtual table module "echo" */ pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; sqlite3_create_module_v2(db, "echo", &echoModule, (void*)pMod, moduleDestroy); + + /* Virtual table module "echo_v2" */ + pMod = sqlite3_malloc(sizeof(EchoModule)); + pMod->interp = interp; + sqlite3_create_module_v2(db, "echo_v2", + &echoModuleV2, (void*)pMod, moduleDestroy + ); return TCL_OK; } diff --git a/src/test_config.c b/src/test_config.c index a2796c77..ce72f873 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -55,6 +55,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "debug", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_DIRECT_OVERFLOW_READ + Tcl_SetVar2(interp, "sqlite_options", "direct_read", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "direct_read", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_DISABLE_DIRSYNC Tcl_SetVar2(interp, "sqlite_options", "dirsync", "0", TCL_GLOBAL_ONLY); #else @@ -363,6 +369,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double", Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_OMIT_MERGE_SORT + Tcl_SetVar2(interp, "sqlite_options", "mergesort", "0", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_OR_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY); #else @@ -412,10 +424,10 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double", Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY); #endif -#ifdef SQLITE_ENABLE_STAT2 - Tcl_SetVar2(interp, "sqlite_options", "stat2", "1", TCL_GLOBAL_ONLY); +#ifdef SQLITE_ENABLE_STAT3 + Tcl_SetVar2(interp, "sqlite_options", "stat3", "1", TCL_GLOBAL_ONLY); #else - Tcl_SetVar2(interp, "sqlite_options", "stat2", "0", TCL_GLOBAL_ONLY); + Tcl_SetVar2(interp, "sqlite_options", "stat3", "0", TCL_GLOBAL_ONLY); #endif #if !defined(SQLITE_ENABLE_LOCKING_STYLE) @@ -571,6 +583,7 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double", LINKVAR( DEFAULT_PAGE_SIZE ); LINKVAR( DEFAULT_FILE_FORMAT ); LINKVAR( MAX_ATTACHED ); + LINKVAR( MAX_DEFAULT_PAGE_SIZE ); { static const int cv_TEMP_STORE = SQLITE_TEMP_STORE; diff --git a/src/test_malloc.c b/src/test_malloc.c index 5023dca4..e955d579 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -1222,7 +1222,7 @@ static int test_dump_memsys3( return TCL_ERROR; } - switch( (int)clientData ){ + switch( SQLITE_PTR_TO_INT(clientData) ){ case 3: { #ifdef SQLITE_ENABLE_MEMSYS3 extern void sqlite3Memsys3Dump(const char*); @@ -1325,11 +1325,13 @@ static int test_db_status( { "STMT_USED", SQLITE_DBSTATUS_STMT_USED }, { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT }, { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE }, - { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL } + { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL }, + { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT }, + { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS } }; Tcl_Obj *pResult; if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); + Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; @@ -1460,7 +1462,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ }; int i; for(i=0; i #include +#include #include "test_multiplex.h" #ifndef SQLITE_CORE @@ -78,20 +84,26 @@ /************************ Shim Definitions ******************************/ -#define SQLITE_MULTIPLEX_VFS_NAME "multiplex" +#ifndef SQLITE_MULTIPLEX_VFS_NAME +# define SQLITE_MULTIPLEX_VFS_NAME "multiplex" +#endif /* This is the limit on the chunk size. It may be changed by calling ** the xFileControl() interface. It will be rounded up to a -** multiple of MAX_PAGE_SIZE. We default it here to 1GB. +** multiple of MAX_PAGE_SIZE. We default it here to 2GiB less 64KiB. */ -#define SQLITE_MULTIPLEX_CHUNK_SIZE (MAX_PAGE_SIZE*16384) +#ifndef SQLITE_MULTIPLEX_CHUNK_SIZE +# define SQLITE_MULTIPLEX_CHUNK_SIZE 2147418112 +#endif /* Default limit on number of chunks. Care should be taken ** so that values for chunks numbers fit in the SQLITE_MULTIPLEX_EXT_FMT ** format specifier. It may be changed by calling ** the xFileControl() interface. */ -#define SQLITE_MULTIPLEX_MAX_CHUNKS 32 +#ifndef SQLITE_MULTIPLEX_MAX_CHUNKS +# define SQLITE_MULTIPLEX_MAX_CHUNKS 32 +#endif /* If SQLITE_MULTIPLEX_EXT_OVWR is defined, the ** last SQLITE_MULTIPLEX_EXT_SZ characters of the @@ -119,13 +131,15 @@ typedef struct multiplexConn multiplexConn; ** group. */ struct multiplexGroup { - sqlite3_file **pReal; /* Handles to each chunk */ - char *bOpen; /* array of bools - 0 if chunk not opened */ + struct multiplexReal { /* For each chunk */ + sqlite3_file *p; /* Handle for the chunk */ + char *z; /* Name of this chunk */ + } *aReal; /* list of all chunks */ + int nReal; /* Number of chunks */ char *zName; /* Base filename of this group */ int nName; /* Length of base filename */ int flags; /* Flags used for original opening */ - int nChunkSize; /* Chunk size used for this group */ - int nMaxChunks; /* Max number of chunks for this group */ + unsigned int szChunk; /* Chunk size used for this group */ int bEnabled; /* TRUE to use Multiplex VFS for this file */ multiplexGroup *pNext, *pPrev; /* Doubly linked list of all group objects */ }; @@ -184,12 +198,6 @@ static struct { /* List of multiplexGroup objects. */ multiplexGroup *pGroups; - - /* Storage for temp file names. Allocated during - ** initialization to the max pathname of the underlying VFS. - */ - char *zName; - } gMultiplex; /************************* Utility Routines *********************************/ @@ -265,7 +273,8 @@ static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){ attempts++; sqlite3_randomness(8, &zBuf[j]); for(i=0; i<8; i++){ - zBuf[j+i] = (char)zChars[ ((unsigned char)zBuf[j+i])%(sizeof(zChars)-1) ]; + unsigned char uc = (unsigned char)zBuf[j+i]; + zBuf[j+i] = (char)zChars[uc%(sizeof(zChars)-1)]; } memcpy(&zBuf[j+i], ".tmp", 5); rc = pOrigVfs->xAccess(pOrigVfs, zBuf, SQLITE_ACCESS_EXISTS, &exists); @@ -279,35 +288,69 @@ static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){ return rc; } +/* Compute the filename for the iChunk-th chunk +*/ +static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){ + if( iChunk>=pGroup->nReal ){ + struct multiplexReal *p; + p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p)); + if( p==0 ){ + return SQLITE_NOMEM; + } + memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal)); + pGroup->aReal = p; + pGroup->nReal = iChunk+1; + } + if( pGroup->aReal[iChunk].z==0 ){ + char *z; + int n = pGroup->nName; + pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+3 ); + if( z==0 ){ + return SQLITE_NOMEM; + } + memcpy(z, pGroup->zName, n+1); + if( iChunk>0 ){ +#ifdef SQLITE_ENABLE_8_3_NAMES + if( n>3 && z[n-3]=='.' ){ + n--; + }else if( n>4 && z[n-4]=='.' ){ + n -= 2; + } +#endif + sqlite3_snprintf(3,&z[n],"%02d",iChunk); + } + } + return SQLITE_OK; +} + /* Translate an sqlite3_file* that is really a multiplexGroup* into ** the sqlite3_file* for the underlying original VFS. */ -static sqlite3_file *multiplexSubOpen(multiplexConn *pConn, int iChunk, int *rc, int *pOutFlags){ - multiplexGroup *pGroup = pConn->pGroup; +static sqlite3_file *multiplexSubOpen( + multiplexGroup *pGroup, + int iChunk, + int *rc, + int *pOutFlags +){ + sqlite3_file *pSubOpen = 0; sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ - if( iChunknMaxChunks ){ - sqlite3_file *pSubOpen = pGroup->pReal[iChunk]; /* Real file descriptor */ - if( !pGroup->bOpen[iChunk] ){ - memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1); - if( iChunk ){ -#ifdef SQLITE_MULTIPLEX_EXT_OVWR - sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ, SQLITE_MULTIPLEX_EXT_FMT, iChunk); -#else - sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName, SQLITE_MULTIPLEX_EXT_FMT, iChunk); -#endif - } - *rc = pOrigVfs->xOpen(pOrigVfs, gMultiplex.zName, pSubOpen, pGroup->flags, pOutFlags); - if( *rc==SQLITE_OK ){ - pGroup->bOpen[iChunk] = -1; - return pSubOpen; - } - return NULL; + *rc = multiplexSubFilename(pGroup, iChunk); + if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){ + pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile ); + if( pSubOpen==0 ){ + *rc = SQLITE_NOMEM; + return 0; + } + pGroup->aReal[iChunk].p = pSubOpen; + *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen, + pGroup->flags, pOutFlags); + if( *rc!=SQLITE_OK ){ + sqlite3_free(pSubOpen); + pGroup->aReal[iChunk].p = 0; + return 0; } - *rc = SQLITE_OK; - return pSubOpen; } - *rc = SQLITE_FULL; - return NULL; + return pSubOpen; } /* @@ -366,6 +409,36 @@ static int multiplexFuncInit( return rc; } +/* +** Close a single sub-file in the connection group. +*/ +static void multiplexSubClose( + multiplexGroup *pGroup, + int iChunk, + sqlite3_vfs *pOrigVfs +){ + sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p; + if( pSubOpen ){ + pSubOpen->pMethods->xClose(pSubOpen); + if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0); + sqlite3_free(pGroup->aReal[iChunk].p); + } + sqlite3_free(pGroup->aReal[iChunk].z); + memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk])); +} + +/* +** Deallocate memory held by a multiplexGroup +*/ +static void multiplexFreeComponents(multiplexGroup *pGroup){ + int i; + for(i=0; inReal; i++){ multiplexSubClose(pGroup, i, 0); } + sqlite3_free(pGroup->aReal); + pGroup->aReal = 0; + pGroup->nReal = 0; +} + + /************************* VFS Method Wrappers *****************************/ /* @@ -382,16 +455,17 @@ static int multiplexOpen( int flags, /* Flags to control the opening */ int *pOutFlags /* Flags showing results of opening */ ){ - int rc = SQLITE_OK; /* Result code */ - multiplexConn *pMultiplexOpen; /* The new multiplex file descriptor */ - multiplexGroup *pGroup; /* Corresponding multiplexGroup object */ - sqlite3_file *pSubOpen; /* Real file descriptor */ + int rc = SQLITE_OK; /* Result code */ + multiplexConn *pMultiplexOpen; /* The new multiplex file descriptor */ + multiplexGroup *pGroup; /* Corresponding multiplexGroup object */ + sqlite3_file *pSubOpen = 0; /* Real file descriptor */ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ int nName; - int i; int sz; + char *zToFree = 0; UNUSED_PARAMETER(pVfs); + memset(pConn, 0, pVfs->szOsFile); /* We need to create a group structure and manage ** access to this group of files. @@ -405,28 +479,22 @@ static int multiplexOpen( ** it. */ if( !zName ){ - rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, gMultiplex.zName); - zName = gMultiplex.zName; + zName = zToFree = sqlite3_malloc( pOrigVfs->mxPathname + 10 ); + if( zName==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, zToFree); + } } if( rc==SQLITE_OK ){ /* allocate space for group */ nName = multiplexStrlen30(zName); - sz = sizeof(multiplexGroup) /* multiplexGroup */ - + (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS) /* pReal[] */ - + (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS) /* *pReal */ - + SQLITE_MULTIPLEX_MAX_CHUNKS /* bOpen[] */ - + nName + 1; /* zName */ -#ifndef SQLITE_MULTIPLEX_EXT_OVWR - sz += SQLITE_MULTIPLEX_EXT_SZ; - assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname); -#else - assert(nName >= SQLITE_MULTIPLEX_EXT_SZ); - assert(nName < pOrigVfs->mxPathname); -#endif + sz = sizeof(multiplexGroup) /* multiplexGroup */ + + nName + 1; /* zName */ pGroup = sqlite3_malloc( sz ); if( pGroup==0 ){ - rc=SQLITE_NOMEM; + rc = SQLITE_NOMEM; } } @@ -436,32 +504,58 @@ static int multiplexOpen( pMultiplexOpen->pGroup = pGroup; memset(pGroup, 0, sz); pGroup->bEnabled = -1; - pGroup->nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE; - pGroup->nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS; - pGroup->pReal = (sqlite3_file **)p; - p += (sizeof(sqlite3_file *)*pGroup->nMaxChunks); - for(i=0; inMaxChunks; i++){ - pGroup->pReal[i] = (sqlite3_file *)p; - p += pOrigVfs->szOsFile; + pGroup->szChunk = SQLITE_MULTIPLEX_CHUNK_SIZE; + if( flags & SQLITE_OPEN_URI ){ + const char *zChunkSize; + zChunkSize = sqlite3_uri_parameter(zName, "chunksize"); + if( zChunkSize ){ + unsigned int n = 0; + int i; + for(i=0; zChunkSize[i]>='0' && zChunkSize[i]<='9'; i++){ + n = n*10 + zChunkSize[i] - '0'; + } + if( n>0 ){ + pGroup->szChunk = (n+0xffff)&~0xffff; + }else{ + /* A zero or negative chunksize disabled the multiplexor */ + pGroup->bEnabled = 0; + } + } } - /* bOpen[] vals should all be zero from memset above */ - pGroup->bOpen = p; - p += pGroup->nMaxChunks; pGroup->zName = p; /* save off base filename, name length, and original open flags */ memcpy(pGroup->zName, zName, nName+1); pGroup->nName = nName; pGroup->flags = flags; - pSubOpen = multiplexSubOpen(pMultiplexOpen, 0, &rc, pOutFlags); + rc = multiplexSubFilename(pGroup, 1); + if( rc==SQLITE_OK ){ + pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags); + } if( pSubOpen ){ - /* if this file is already larger than chunk size, disable - ** the multiplex feature. - */ + int exists, rc2, rc3; sqlite3_int64 sz; - int rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz); - if( (rc2==SQLITE_OK) && (sz>pGroup->nChunkSize) ){ - pGroup->bEnabled = 0; + + rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz); + if( rc2==SQLITE_OK ){ + /* If the first overflow file exists and if the size of the main file + ** is different from the chunk size, that means the chunk size is set + ** set incorrectly. So fix it. + ** + ** Or, if the first overflow file does not exist and the main file is + ** larger than the chunk size, that means the chunk size is too small. + ** But we have no way of determining the intended chunk size, so + ** just disable the multiplexor all togethre. + */ + rc3 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z, + SQLITE_ACCESS_EXISTS, &exists); + if( rc3==SQLITE_OK && exists && sz==(sz&0xffff0000) && sz>0 + && sz!=pGroup->szChunk ){ + pGroup->szChunk = sz; + }else if( rc3==SQLITE_OK && !exists && sz>pGroup->szChunk ){ + pGroup->bEnabled = 0; + } } + if( pSubOpen->pMethods->iVersion==1 ){ pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1; }else{ @@ -472,17 +566,18 @@ static int multiplexOpen( if( gMultiplex.pGroups ) gMultiplex.pGroups->pPrev = pGroup; gMultiplex.pGroups = pGroup; }else{ + multiplexFreeComponents(pGroup); sqlite3_free(pGroup); } } multiplexLeave(); + sqlite3_free(zToFree); return rc; } /* ** This is the xDelete method used for the "multiplex" VFS. -** It attempts to delete the filename specified, as well -** as additional files with the SQLITE_MULTIPLEX_EXT_FMT extension. +** It attempts to delete the filename specified. */ static int multiplexDelete( sqlite3_vfs *pVfs, /* The multiplex VFS */ @@ -490,41 +585,7 @@ static int multiplexDelete( int syncDir ){ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ - int rc = SQLITE_OK; - int nName = multiplexStrlen30(zName); - int i; - - UNUSED_PARAMETER(pVfs); - - multiplexEnter(); - memcpy(gMultiplex.zName, zName, nName+1); - for(i=0; ixAccess(pOrigVfs, gMultiplex.zName, - SQLITE_ACCESS_EXISTS, &exists); - if( rc2==SQLITE_OK && exists ){ - /* if it exists, delete it */ - rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir); - if( rc2!=SQLITE_OK ) rc = rc2; - }else{ - /* stop at first "gap" */ - break; - } - } - multiplexLeave(); - return rc; + return pOrigVfs->xDelete(pOrigVfs, zName, syncDir); } static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){ @@ -572,17 +633,8 @@ static int multiplexClose(sqlite3_file *pConn){ multiplexConn *p = (multiplexConn*)pConn; multiplexGroup *pGroup = p->pGroup; int rc = SQLITE_OK; - int i; multiplexEnter(); - /* close any open handles */ - for(i=0; inMaxChunks; i++){ - if( pGroup->bOpen[i] ){ - sqlite3_file *pSubOpen = pGroup->pReal[i]; - int rc2 = pSubOpen->pMethods->xClose(pSubOpen); - if( rc2!=SQLITE_OK ) rc = rc2; - pGroup->bOpen[i] = 0; - } - } + multiplexFreeComponents(pGroup); /* remove from linked list */ if( pGroup->pNext ) pGroup->pNext->pPrev = pGroup->pPrev; if( pGroup->pPrev ){ @@ -610,17 +662,22 @@ static int multiplexRead( int rc = SQLITE_OK; multiplexEnter(); if( !pGroup->bEnabled ){ - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); - rc = ( !pSubOpen ) ? SQLITE_IOERR_READ : pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst); + sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL); + if( pSubOpen==0 ){ + rc = SQLITE_IOERR_READ; + }else{ + rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst); + } }else{ while( iAmt > 0 ){ - int i = (int)(iOfst / pGroup->nChunkSize); - sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL); + int i = (int)(iOfst / pGroup->szChunk); + sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL); if( pSubOpen ){ - int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) - pGroup->nChunkSize; + int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk; if( extra<0 ) extra = 0; iAmt -= extra; - rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst % pGroup->nChunkSize); + rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, + iOfst % pGroup->szChunk); if( rc!=SQLITE_OK ) break; pBuf = (char *)pBuf + iAmt; iOfst += iAmt; @@ -650,17 +707,23 @@ static int multiplexWrite( int rc = SQLITE_OK; multiplexEnter(); if( !pGroup->bEnabled ){ - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); - rc = ( !pSubOpen ) ? SQLITE_IOERR_WRITE : pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); + sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL); + if( pSubOpen==0 ){ + rc = SQLITE_IOERR_WRITE; + }else{ + rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); + } }else{ while( iAmt > 0 ){ - int i = (int)(iOfst / pGroup->nChunkSize); - sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL); + int i = (int)(iOfst / pGroup->szChunk); + sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL); if( pSubOpen ){ - int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) - pGroup->nChunkSize; + int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - + pGroup->szChunk; if( extra<0 ) extra = 0; iAmt -= extra; - rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst % pGroup->nChunkSize); + rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, + iOfst % pGroup->szChunk); if( rc!=SQLITE_OK ) break; pBuf = (char *)pBuf + iAmt; iOfst += iAmt; @@ -685,38 +748,24 @@ static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){ int rc = SQLITE_OK; multiplexEnter(); if( !pGroup->bEnabled ){ - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); - rc = ( !pSubOpen ) ? SQLITE_IOERR_TRUNCATE : pSubOpen->pMethods->xTruncate(pSubOpen, size); + sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL); + if( pSubOpen==0 ){ + rc = SQLITE_IOERR_TRUNCATE; + }else{ + rc = pSubOpen->pMethods->xTruncate(pSubOpen, size); + } }else{ int rc2; int i; sqlite3_file *pSubOpen; sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ - memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1); /* delete the chunks above the truncate limit */ - for(i=(int)(size / pGroup->nChunkSize)+1; inMaxChunks; i++){ - /* close any open chunks before deleting them */ - if( pGroup->bOpen[i] ){ - pSubOpen = pGroup->pReal[i]; - rc2 = pSubOpen->pMethods->xClose(pSubOpen); - if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE; - pGroup->bOpen[i] = 0; - } -#ifdef SQLITE_MULTIPLEX_EXT_OVWR - sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, - gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ, - SQLITE_MULTIPLEX_EXT_FMT, i); -#else - sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, - gMultiplex.zName+pGroup->nName, - SQLITE_MULTIPLEX_EXT_FMT, i); -#endif - rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, 0); - if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE; + for(i=(int)(size / pGroup->szChunk)+1; inReal; i++){ + multiplexSubClose(pGroup, i, pOrigVfs); } - pSubOpen = multiplexSubOpen(p, (int)(size / pGroup->nChunkSize), &rc2, NULL); + pSubOpen = multiplexSubOpen(pGroup, (int)(size/pGroup->szChunk), &rc2,0); if( pSubOpen ){ - rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->nChunkSize); + rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk); if( rc2!=SQLITE_OK ) rc = rc2; }else{ rc = SQLITE_IOERR_TRUNCATE; @@ -734,10 +783,9 @@ static int multiplexSync(sqlite3_file *pConn, int flags){ int rc = SQLITE_OK; int i; multiplexEnter(); - for(i=0; inMaxChunks; i++){ - /* if we don't have it open, we don't need to sync it */ - if( pGroup->bOpen[i] ){ - sqlite3_file *pSubOpen = pGroup->pReal[i]; + for(i=0; inReal; i++){ + sqlite3_file *pSubOpen = pGroup->aReal[i].p; + if( pSubOpen ){ int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags); if( rc2!=SQLITE_OK ) rc = rc2; } @@ -757,39 +805,28 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){ int i; multiplexEnter(); if( !pGroup->bEnabled ){ - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); - rc = ( !pSubOpen ) ? SQLITE_IOERR_FSTAT : pSubOpen->pMethods->xFileSize(pSubOpen, pSize); + sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL); + if( pSubOpen==0 ){ + rc = SQLITE_IOERR_FSTAT; + }else{ + rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize); + } }else{ + sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; *pSize = 0; - for(i=0; inMaxChunks; i++){ - sqlite3_file *pSubOpen = NULL; - /* if not opened already, check to see if the chunk exists */ - if( pGroup->bOpen[i] ){ - pSubOpen = pGroup->pReal[i]; + for(i=0; 1; i++){ + sqlite3_file *pSubOpen = 0; + int exists = 0; + rc = multiplexSubFilename(pGroup, i); + if( rc ) break; + rc2 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[i].z, + SQLITE_ACCESS_EXISTS, &exists); + if( rc2==SQLITE_OK && exists){ + /* if it exists, open it */ + pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL); }else{ - sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ - int exists = 0; - memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1); - if( i ){ -#ifdef SQLITE_MULTIPLEX_EXT_OVWR - sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, - gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ, - SQLITE_MULTIPLEX_EXT_FMT, i); -#else - sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, - gMultiplex.zName+pGroup->nName, - SQLITE_MULTIPLEX_EXT_FMT, i); -#endif - } - rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, - SQLITE_ACCESS_EXISTS, &exists); - if( rc2==SQLITE_OK && exists){ - /* if it exists, open it */ - pSubOpen = multiplexSubOpen(p, i, &rc, NULL); - }else{ - /* stop at first "gap" */ - break; - } + /* stop at first "gap" */ + break; } if( pSubOpen ){ sqlite3_int64 sz; @@ -797,7 +834,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){ if( rc2!=SQLITE_OK ){ rc = rc2; }else{ - if( sz>pGroup->nChunkSize ){ + if( sz>pGroup->szChunk ){ rc = SQLITE_IOERR_FSTAT; } *pSize += sz; @@ -816,7 +853,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){ static int multiplexLock(sqlite3_file *pConn, int lock){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ return pSubOpen->pMethods->xLock(pSubOpen, lock); } @@ -828,7 +865,7 @@ static int multiplexLock(sqlite3_file *pConn, int lock){ static int multiplexUnlock(sqlite3_file *pConn, int lock){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ return pSubOpen->pMethods->xUnlock(pSubOpen, lock); } @@ -840,7 +877,7 @@ static int multiplexUnlock(sqlite3_file *pConn, int lock){ static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut); } @@ -867,28 +904,20 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){ break; case MULTIPLEX_CTRL_SET_CHUNK_SIZE: if( pArg ) { - int nChunkSize = *(int *)pArg; - if( nChunkSize<1 ){ + unsigned int szChunk = *(unsigned*)pArg; + if( szChunk<1 ){ rc = SQLITE_MISUSE; }else{ /* Round up to nearest multiple of MAX_PAGE_SIZE. */ - nChunkSize = (nChunkSize + (MAX_PAGE_SIZE-1)); - nChunkSize &= ~(MAX_PAGE_SIZE-1); - pGroup->nChunkSize = nChunkSize; + szChunk = (szChunk + (MAX_PAGE_SIZE-1)); + szChunk &= ~(MAX_PAGE_SIZE-1); + pGroup->szChunk = szChunk; rc = SQLITE_OK; } } break; case MULTIPLEX_CTRL_SET_MAX_CHUNKS: - if( pArg ) { - int nMaxChunks = *(int *)pArg; - if(( nMaxChunks<1 ) || ( nMaxChunks>SQLITE_MULTIPLEX_MAX_CHUNKS )){ - rc = SQLITE_MISUSE; - }else{ - pGroup->nMaxChunks = nMaxChunks; - rc = SQLITE_OK; - } - } + rc = SQLITE_OK; break; case SQLITE_FCNTL_SIZE_HINT: case SQLITE_FCNTL_CHUNK_SIZE: @@ -896,7 +925,7 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){ rc = SQLITE_OK; break; default: - pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL); if( pSubOpen ){ rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg); } @@ -910,7 +939,7 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){ static int multiplexSectorSize(sqlite3_file *pConn){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ return pSubOpen->pMethods->xSectorSize(pSubOpen); } @@ -922,7 +951,7 @@ static int multiplexSectorSize(sqlite3_file *pConn){ static int multiplexDeviceCharacteristics(sqlite3_file *pConn){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen); } @@ -940,9 +969,9 @@ static int multiplexShmMap( ){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ - return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend, pp); + return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp); } return SQLITE_IOERR; } @@ -957,7 +986,7 @@ static int multiplexShmLock( ){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags); } @@ -969,7 +998,7 @@ static int multiplexShmLock( static void multiplexShmBarrier(sqlite3_file *pConn){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ pSubOpen->pMethods->xShmBarrier(pSubOpen); } @@ -980,7 +1009,7 @@ static void multiplexShmBarrier(sqlite3_file *pConn){ static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){ multiplexConn *p = (multiplexConn*)pConn; int rc; - sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL); + sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL); if( pSubOpen ){ return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag); } @@ -1010,11 +1039,6 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){ if( !gMultiplex.pMutex ){ return SQLITE_NOMEM; } - gMultiplex.zName = sqlite3_malloc(pOrigVfs->mxPathname); - if( !gMultiplex.zName ){ - sqlite3_mutex_free(gMultiplex.pMutex); - return SQLITE_NOMEM; - } gMultiplex.pGroups = NULL; gMultiplex.isInitialized = 1; gMultiplex.pOrigVfs = pOrigVfs; @@ -1047,7 +1071,8 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){ gMultiplex.sIoMethodsV1.xCheckReservedLock = multiplexCheckReservedLock; gMultiplex.sIoMethodsV1.xFileControl = multiplexFileControl; gMultiplex.sIoMethodsV1.xSectorSize = multiplexSectorSize; - gMultiplex.sIoMethodsV1.xDeviceCharacteristics = multiplexDeviceCharacteristics; + gMultiplex.sIoMethodsV1.xDeviceCharacteristics = + multiplexDeviceCharacteristics; gMultiplex.sIoMethodsV2 = gMultiplex.sIoMethodsV1; gMultiplex.sIoMethodsV2.iVersion = 2; gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap; @@ -1074,7 +1099,6 @@ int sqlite3_multiplex_shutdown(void){ if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE; if( gMultiplex.pGroups ) return SQLITE_MISUSE; gMultiplex.isInitialized = 0; - sqlite3_free(gMultiplex.zName); sqlite3_mutex_free(gMultiplex.pMutex); sqlite3_vfs_unregister(&gMultiplex.sThisVfs); memset(&gMultiplex, 0, sizeof(gMultiplex)); @@ -1176,16 +1200,16 @@ static int test_multiplex_dump( Tcl_NewIntObj(pGroup->flags)); /* count number of chunks with open handles */ - for(i=0; inMaxChunks; i++){ - if( pGroup->bOpen[i] ) nChunks++; + for(i=0; inReal; i++){ + if( pGroup->aReal[i].p!=0 ) nChunks++; } Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_NewIntObj(nChunks)); Tcl_ListObjAppendElement(interp, pGroupTerm, - Tcl_NewIntObj(pGroup->nChunkSize)); + Tcl_NewIntObj(pGroup->szChunk)); Tcl_ListObjAppendElement(interp, pGroupTerm, - Tcl_NewIntObj(pGroup->nMaxChunks)); + Tcl_NewIntObj(pGroup->nReal)); Tcl_ListObjAppendElement(interp, pResult, pGroupTerm); } diff --git a/src/test_quota.c b/src/test_quota.c index 9b0e4a9d..74d1a6d3 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -95,6 +95,7 @@ struct quotaFile { quotaGroup *pGroup; /* Quota group to which this file belongs */ sqlite3_int64 iSize; /* Current size of this file */ int nRef; /* Number of times this file is open */ + int deleteOnClose; /* True to delete this file when it closes */ quotaFile *pNext, **ppPrev; /* Linked list of files in the same group */ }; @@ -164,12 +165,45 @@ static struct { static void quotaEnter(void){ sqlite3_mutex_enter(gQuota.pMutex); } static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); } +/* Count the number of open files in a quotaGroup +*/ +static int quotaGroupOpenFileCount(quotaGroup *pGroup){ + int N = 0; + quotaFile *pFile = pGroup->pFiles; + while( pFile ){ + if( pFile->nRef ) N++; + pFile = pFile->pNext; + } + return N; +} + +/* Remove a file from a quota group. +*/ +static void quotaRemoveFile(quotaFile *pFile){ + quotaGroup *pGroup = pFile->pGroup; + pGroup->iSize -= pFile->iSize; + *pFile->ppPrev = pFile->pNext; + if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev; + sqlite3_free(pFile); +} + +/* Remove all files from a quota group. It is always the case that +** all files will be closed when this routine is called. +*/ +static void quotaRemoveAllFiles(quotaGroup *pGroup){ + while( pGroup->pFiles ){ + assert( pGroup->pFiles->nRef==0 ); + quotaRemoveFile(pGroup->pFiles); + } +} + /* If the reference count and threshold for a quotaGroup are both ** zero, then destroy the quotaGroup. */ static void quotaGroupDeref(quotaGroup *pGroup){ - if( pGroup->pFiles==0 && pGroup->iLimit==0 ){ + if( pGroup->iLimit==0 && quotaGroupOpenFileCount(pGroup)==0 ){ + quotaRemoveAllFiles(pGroup); *pGroup->ppPrev = pGroup->pNext; if( pGroup->pNext ) pGroup->pNext->ppPrev = pGroup->ppPrev; if( pGroup->xDestroy ) pGroup->xDestroy(pGroup->pArg); @@ -276,6 +310,17 @@ static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){ return (sqlite3_file*)&p[1]; } +/* Find a file in a quota group and return a pointer to that file. +** Return NULL if the file is not in the group. +*/ +static quotaFile *quotaFindFile(quotaGroup *pGroup, const char *zName){ + quotaFile *pFile = pGroup->pFiles; + while( pFile && strcmp(pFile->zFilename, zName)!=0 ){ + pFile = pFile->pNext; + } + return pFile; +} + /************************* VFS Method Wrappers *****************************/ /* ** This is the xOpen method used for the "quota" VFS. @@ -319,8 +364,7 @@ static int quotaOpen( pSubOpen = quotaSubOpen(pConn); rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags); if( rc==SQLITE_OK ){ - for(pFile=pGroup->pFiles; pFile && strcmp(pFile->zFilename, zName); - pFile=pFile->pNext){} + pFile = quotaFindFile(pGroup, zName); if( pFile==0 ){ int nName = strlen(zName); pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 ); @@ -337,6 +381,7 @@ static int quotaOpen( pFile->ppPrev = &pGroup->pFiles; pGroup->pFiles = pFile; pFile->pGroup = pGroup; + pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0; } pFile->nRef++; pQuotaOpen->pFile = pFile; @@ -351,6 +396,49 @@ static int quotaOpen( return rc; } +/* +** This is the xDelete method used for the "quota" VFS. +** +** If the file being deleted is part of the quota group, then reduce +** the size of the quota group accordingly. And remove the file from +** the set of files in the quota group. +*/ +static int quotaDelete( + sqlite3_vfs *pVfs, /* The quota VFS */ + const char *zName, /* Name of file to be deleted */ + int syncDir /* Do a directory sync after deleting */ +){ + int rc; /* Result code */ + quotaFile *pFile; /* Files in the quota */ + quotaGroup *pGroup; /* The group file belongs to */ + sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs; /* Real VFS */ + + /* Do the actual file delete */ + rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir); + + /* If the file just deleted is a member of a quota group, then remove + ** it from that quota group. + */ + if( rc==SQLITE_OK ){ + quotaEnter(); + pGroup = quotaGroupFind(zName); + if( pGroup ){ + pFile = quotaFindFile(pGroup, zName); + if( pFile ){ + if( pFile->nRef ){ + pFile->deleteOnClose = 1; + }else{ + quotaRemoveFile(pFile); + quotaGroupDeref(pGroup); + } + } + } + quotaLeave(); + } + return rc; +} + + /************************ I/O Method Wrappers *******************************/ /* xClose requests get passed through to the original VFS. But we @@ -367,11 +455,8 @@ static int quotaClose(sqlite3_file *pConn){ pFile->nRef--; if( pFile->nRef==0 ){ quotaGroup *pGroup = pFile->pGroup; - pGroup->iSize -= pFile->iSize; - if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev; - *pFile->ppPrev = pFile->pNext; + if( pFile->deleteOnClose ) quotaRemoveFile(pFile); quotaGroupDeref(pGroup); - sqlite3_free(pFile); } quotaLeave(); return rc; @@ -586,6 +671,7 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){ gQuota.pOrigVfs = pOrigVfs; gQuota.sThisVfs = *pOrigVfs; gQuota.sThisVfs.xOpen = quotaOpen; + gQuota.sThisVfs.xDelete = quotaDelete; gQuota.sThisVfs.szOsFile += sizeof(quotaConn); gQuota.sThisVfs.zName = "quota"; gQuota.sIoMethodsV1.iVersion = 1; @@ -617,19 +703,20 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){ ** All SQLite database connections must be closed before calling this ** routine. ** -** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly one while +** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while ** shutting down in order to free all remaining quota groups. */ int sqlite3_quota_shutdown(void){ quotaGroup *pGroup; if( gQuota.isInitialized==0 ) return SQLITE_MISUSE; for(pGroup=gQuota.pGroup; pGroup; pGroup=pGroup->pNext){ - if( pGroup->pFiles ) return SQLITE_MISUSE; + if( quotaGroupOpenFileCount(pGroup)>0 ) return SQLITE_MISUSE; } while( gQuota.pGroup ){ pGroup = gQuota.pGroup; gQuota.pGroup = pGroup->pNext; pGroup->iLimit = 0; + assert( quotaGroupOpenFileCount(pGroup)==0 ); quotaGroupDeref(pGroup); } gQuota.isInitialized = 0; @@ -708,6 +795,43 @@ int sqlite3_quota_set( return SQLITE_OK; } +/* +** Bring the named file under quota management. Or if it is already under +** management, update its size. +*/ +int sqlite3_quota_file(const char *zFilename){ + char *zFull; + sqlite3_file *fd; + int rc; + int outFlags = 0; + sqlite3_int64 iSize; + fd = sqlite3_malloc(gQuota.sThisVfs.szOsFile + gQuota.sThisVfs.mxPathname+1); + if( fd==0 ) return SQLITE_NOMEM; + zFull = gQuota.sThisVfs.szOsFile + (char*)fd; + rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, + gQuota.sThisVfs.mxPathname+1, zFull); + if( rc==SQLITE_OK ){ + rc = quotaOpen(&gQuota.sThisVfs, zFull, fd, + SQLITE_OPEN_READONLY | SQLITE_OPEN_MAIN_DB, &outFlags); + } + if( rc==SQLITE_OK ){ + fd->pMethods->xFileSize(fd, &iSize); + fd->pMethods->xClose(fd); + }else if( rc==SQLITE_CANTOPEN ){ + quotaGroup *pGroup; + quotaFile *pFile; + quotaEnter(); + pGroup = quotaGroupFind(zFull); + if( pGroup ){ + pFile = quotaFindFile(pGroup, zFull); + if( pFile ) quotaRemoveFile(pFile); + } + quotaLeave(); + } + sqlite3_free(fd); + return rc; +} + /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST @@ -884,6 +1008,32 @@ static int test_quota_set( return TCL_OK; } +/* +** tclcmd: sqlite3_quota_file FILENAME +*/ +static int test_quota_file( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + const char *zFilename; /* File pattern to configure */ + int rc; /* Value returned by quota_file() */ + + /* Process arguments */ + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); + return TCL_ERROR; + } + zFilename = Tcl_GetString(objv[1]); + + /* Invoke sqlite3_quota_file() */ + rc = sqlite3_quota_file(zFilename); + + Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); + return TCL_OK; +} + /* ** tclcmd: sqlite3_quota_dump */ @@ -917,6 +1067,8 @@ static int test_quota_dump( Tcl_NewWideIntObj(pFile->iSize)); Tcl_ListObjAppendElement(interp, pFileTerm, Tcl_NewWideIntObj(pFile->nRef)); + Tcl_ListObjAppendElement(interp, pFileTerm, + Tcl_NewWideIntObj(pFile->deleteOnClose)); Tcl_ListObjAppendElement(interp, pGroupTerm, pFileTerm); } Tcl_ListObjAppendElement(interp, pResult, pGroupTerm); @@ -939,6 +1091,7 @@ int Sqlitequota_Init(Tcl_Interp *interp){ { "sqlite3_quota_initialize", test_quota_initialize }, { "sqlite3_quota_shutdown", test_quota_shutdown }, { "sqlite3_quota_set", test_quota_set }, + { "sqlite3_quota_file", test_quota_file }, { "sqlite3_quota_dump", test_quota_dump }, }; int i; diff --git a/src/test_rtree.c b/src/test_rtree.c index 5fc994dd..9745b005 100644 --- a/src/test_rtree.c +++ b/src/test_rtree.c @@ -18,6 +18,7 @@ /* Solely for the UNUSED_PARAMETER() macro. */ #include "sqliteInt.h" +#ifdef SQLITE_ENABLE_RTREE /* ** Type used to cache parameter information for the "circle" r-tree geometry ** callback. @@ -230,6 +231,7 @@ static int cube_geom( return SQLITE_OK; } +#endif /* SQLITE_ENABLE_RTREE */ static int register_cube_geom( void * clientData, diff --git a/src/test_stat.c b/src/test_stat.c index c85463e5..ef817690 100644 --- a/src/test_stat.c +++ b/src/test_stat.c @@ -18,7 +18,9 @@ ** for an example implementation. */ -#include "sqliteInt.h" +#ifndef SQLITE_AMALGAMATION +# include "sqliteInt.h" +#endif #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -62,20 +64,11 @@ " 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 */" \ + " mx_payload INTEGER, /* Largest payload size of all cells */" \ + " pgoffset INTEGER, /* Offset of page in file */" \ + " pgsize INTEGER /* Size of the page */" \ ");" -#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; @@ -124,6 +117,8 @@ struct StatCursor { int nPayload; /* Value of 'payload' column */ int nUnused; /* Value of 'unused' column */ int nMxPayload; /* Value of 'mx_payload' column */ + i64 iOffset; /* Value of 'pgOffset' column */ + int szPage; /* Value of 'pgSize' column */ }; struct StatTable { @@ -281,6 +276,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ int iOff; int nHdr; int isLeaf; + int szPage; u8 *aData = sqlite3PagerGetData(p->pPg); u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; @@ -301,10 +297,11 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } p->nUnused = nUnused; p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); + szPage = sqlite3BtreeGetPageSize(pBt); if( p->nCell ){ int i; /* Used to iterate through cells */ - int nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt); + int nUsable = szPage - sqlite3BtreeGetReserve(pBt); p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell)); memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); @@ -359,6 +356,32 @@ static int statDecodePage(Btree *pBt, StatPage *p){ return SQLITE_OK; } +/* +** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on +** the current value of pCsr->iPageno. +*/ +static void statSizeAndOffset(StatCursor *pCsr){ + StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab; + Btree *pBt = pTab->db->aDb[0].pBt; + Pager *pPager = sqlite3BtreePager(pBt); + sqlite3_file *fd; + sqlite3_int64 x[2]; + + /* The default page size and offset */ + pCsr->szPage = sqlite3BtreeGetPageSize(pBt); + pCsr->iOffset = pCsr->szPage * (pCsr->iPageno - 1); + + /* If connected to a ZIPVFS backend, override the page size and + ** offset with actual values obtained from ZIPVFS. + */ + fd = sqlite3PagerFile(pPager); + x[0] = pCsr->iPageno; + if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ + pCsr->iOffset = x[0]; + pCsr->szPage = x[1]; + } +} + /* ** Move a statvfs cursor to the next entry in the file. */ @@ -417,6 +440,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->nUnused = nUsable - 4 - pCsr->nPayload; } pCell->iOvfl++; + statSizeAndOffset(pCsr); return SQLITE_OK; } if( p->iRightChildPg ) break; @@ -454,6 +478,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->iPageno = p->iPgno; statDecodePage(pBt, p); + statSizeAndOffset(pCsr); switch( p->flags ){ case 0x05: /* table internal */ @@ -529,6 +554,12 @@ static int statColumn( case 7: /* mx_payload */ sqlite3_result_int(ctx, pCsr->nMxPayload); break; + case 8: /* pgoffset */ + sqlite3_result_int64(ctx, pCsr->iOffset); + break; + case 9: /* pgsize */ + sqlite3_result_int(ctx, pCsr->szPage); + break; } return SQLITE_OK; } @@ -568,7 +599,7 @@ int sqlite3_dbstat_register(sqlite3 *db){ #endif -#ifdef SQLITE_TEST +#if defined(SQLITE_TEST) || TCLSH==2 #include static int test_dbstat( @@ -604,4 +635,4 @@ int SqlitetestStat_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0); return TCL_OK; } -#endif +#endif /* if defined(SQLITE_TEST) || TCLSH==2 */ diff --git a/src/test_syscall.c b/src/test_syscall.c index b8b05c59..d484f22d 100644 --- a/src/test_syscall.c +++ b/src/test_syscall.c @@ -325,6 +325,7 @@ static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){ */ static int ts_write(int fd, const void *aBuf, size_t nBuf){ if( tsIsFailErrno("write") ){ + if( tsErrno("write")==EINTR ) orig_write(fd, aBuf, nBuf/2); return -1; } return orig_write(fd, aBuf, nBuf); @@ -671,4 +672,3 @@ int SqlitetestSyscall_Init(Tcl_Interp *interp){ return TCL_OK; } #endif - diff --git a/src/test_thread.c b/src/test_thread.c index 3a13dd66..aa894670 100644 --- a/src/test_thread.c +++ b/src/test_thread.c @@ -282,6 +282,21 @@ static int sqlthread_open( zFilename = Tcl_GetString(objv[2]); rc = sqlite3_open(zFilename, &db); +#ifdef SQLITE_HAS_CODEC + if( db && objc>=4 ){ + const char *zKey; + int nKey; + zKey = Tcl_GetStringFromObj(objv[3], &nKey); + rc = sqlite3_key(db, zKey, nKey); + if( rc!=SQLITE_OK ){ + char *zErrMsg = sqlite3_mprintf("error %d: %s", rc, sqlite3_errmsg(db)); + sqlite3_close(db); + Tcl_AppendResult(interp, zErrMsg, (char*)0); + sqlite3_free(zErrMsg); + return TCL_ERROR; + } + } +#endif Md5_Register(db); sqlite3_busy_handler(db, xBusy, 0); @@ -305,7 +320,7 @@ static int sqlthread_id( Tcl_Obj *CONST objv[] ){ Tcl_ThreadId id = Tcl_GetCurrentThread(); - Tcl_SetObjResult(interp, Tcl_NewIntObj((int)id)); + Tcl_SetObjResult(interp, Tcl_NewIntObj(SQLITE_PTR_TO_INT(id))); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); @@ -349,7 +364,7 @@ static int sqlthread_proc( if( rc!=TCL_OK ) return rc; pSub = &aSub[iIndex]; - if( objc!=(pSub->nArg+2) ){ + if( objc<(pSub->nArg+2) ){ Tcl_WrongNumArgs(interp, 2, objv, pSub->zUsage); return TCL_ERROR; } diff --git a/src/test_vfs.c b/src/test_vfs.c index a8b53526..546cb7cf 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -123,6 +123,8 @@ struct Testvfs { #define TESTVFS_TRUNCATE_MASK 0x00002000 #define TESTVFS_ACCESS_MASK 0x00004000 #define TESTVFS_FULLPATHNAME_MASK 0x00008000 +#define TESTVFS_READ_MASK 0x00010000 + #define TESTVFS_ALL_MASK 0x0001FFFF @@ -325,8 +327,22 @@ static int tvfsRead( int iAmt, sqlite_int64 iOfst ){ - TestvfsFd *p = tvfsGetFd(pFile); - return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); + int rc = SQLITE_OK; + TestvfsFd *pFd = tvfsGetFd(pFile); + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->pScript && p->mask&TESTVFS_READ_MASK ){ + tvfsExecTcl(p, "xRead", + Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 + ); + tvfsResultCode(p, &rc); + } + if( rc==SQLITE_OK && p->mask&TESTVFS_READ_MASK && tvfsInjectIoerr(p) ){ + rc = SQLITE_IOERR; + } + if( rc==SQLITE_OK ){ + rc = sqlite3OsRead(pFd->pReal, zBuf, iAmt, iOfst); + } + return rc; } /* @@ -1030,6 +1046,7 @@ static int testvfs_obj_cmd( { "xSync", TESTVFS_SYNC_MASK }, { "xDelete", TESTVFS_DELETE_MASK }, { "xWrite", TESTVFS_WRITE_MASK }, + { "xRead", TESTVFS_READ_MASK }, { "xTruncate", TESTVFS_TRUNCATE_MASK }, { "xOpen", TESTVFS_OPEN_MASK }, { "xClose", TESTVFS_CLOSE_MASK }, diff --git a/src/trigger.c b/src/trigger.c index 6242de5e..22c4877b 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -117,15 +117,28 @@ void sqlite3BeginTrigger( goto trigger_cleanup; } } + if( !pTableName || db->mallocFailed ){ + goto trigger_cleanup; + } + + /* A long-standing parser bug is that this syntax was allowed: + ** + ** CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab .... + ** ^^^^^^^^ + ** + ** To maintain backwards compatibility, ignore the database + ** name on pTableName if we are reparsing our of SQLITE_MASTER. + */ + if( db->init.busy && iDb!=1 ){ + sqlite3DbFree(db, pTableName->a[0].zDatabase); + pTableName->a[0].zDatabase = 0; + } /* If the trigger name was unqualified, and the table is a temp table, ** then set iDb to 1 to create the trigger in the temporary database. ** If sqlite3SrcListLookup() returns 0, indicating the table does not ** exist, the error is caught by the block below. */ - if( !pTableName || db->mallocFailed ){ - goto trigger_cleanup; - } pTab = sqlite3SrcListLookup(pParse, pTableName); if( db->init.busy==0 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ diff --git a/src/update.c b/src/update.c index d445f01f..1e305221 100644 --- a/src/update.c +++ b/src/update.c @@ -311,7 +311,9 @@ void sqlite3Update( /* Begin the database scan */ sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0, WHERE_ONEPASS_DESIRED); + pWInfo = sqlite3WhereBegin( + pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED + ); if( pWInfo==0 ) goto update_cleanup; okOnePass = pWInfo->okOnePass; @@ -354,6 +356,7 @@ void sqlite3Update( } } for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ + assert( aRegIdx ); if( openAll || aRegIdx[i]>0 ){ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb, @@ -527,6 +530,7 @@ void sqlite3Update( /* Close all tables */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ + assert( aRegIdx ); if( openAll || aRegIdx[i]>0 ){ sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0); } diff --git a/src/utf.c b/src/utf.c index 17f3a09a..e94815b5 100644 --- a/src/utf.c +++ b/src/utf.c @@ -464,7 +464,7 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){ ** If a malloc failure occurs, NULL is returned and the db.mallocFailed ** flag set. */ -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 char *sqlite3Utf8to16(sqlite3 *db, u8 enc, char *z, int n, int *pnOut){ Mem m; memset(&m, 0, sizeof(m)); diff --git a/src/util.c b/src/util.c index de735772..3356417e 100644 --- a/src/util.c +++ b/src/util.c @@ -331,7 +331,7 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ } /* copy digits to exponent */ while( z=342 ){ + if( esign<0 ){ + result = 0.0*s; + }else{ + result = 1e308*1e308*s; /* Infinity */ + } }else{ /* 1.0e+22 is the largest power of 10 than can be ** represented exactly. */ @@ -1149,12 +1155,15 @@ int sqlite3AbsInt32(int x){ #ifdef SQLITE_ENABLE_8_3_NAMES /* -** If SQLITE_ENABLE_8_3_NAME is set at compile-time and if the database +** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database ** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and ** if filename in z[] has a suffix (a.k.a. "extension") that is longer than ** three characters, then shorten the suffix on z[] to be the last three ** characters of the original suffix. ** +** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always +** do the suffix shortening regardless of URI parameter. +** ** Examples: ** ** test.db-journal => test.nal @@ -1162,9 +1171,12 @@ int sqlite3AbsInt32(int x){ ** test.db-shm => test.shm */ void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ +#if SQLITE_ENABLE_8_3_NAMES<2 const char *zOk; zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names"); - if( zOk && sqlite3GetBoolean(zOk) ){ + if( zOk && sqlite3GetBoolean(zOk) ) +#endif + { int i, sz; sz = sqlite3Strlen30(z); for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} diff --git a/src/vacuum.c b/src/vacuum.c index 5a4ed320..58a3c9d6 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -45,7 +45,7 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ return sqlite3_errcode(db); } VVA_ONLY( rc = ) sqlite3_step(pStmt); - assert( rc!=SQLITE_ROW ); + assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) ); return vacuumFinalize(db, pStmt, pzErrMsg); } @@ -263,13 +263,11 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ ); if( rc ) goto end_of_vacuum; - /* At this point, unless the main db was completely empty, there is now a - ** transaction open on the vacuum database, but not on the main database. - ** Open a btree level transaction on the main database. This allows a - ** call to sqlite3BtreeCopyFile(). The main database btree level - ** transaction is then committed, so the SQL level never knows it was - ** opened for writing. This way, the SQL transaction used to create the - ** temporary database never needs to be committed. + /* At this point, there is a write transaction open on both the + ** vacuum database and the main database. Assuming no error occurs, + ** both transactions are closed by this block - the main database + ** transaction by sqlite3BtreeCopyFile() and the other by an explicit + ** call to sqlite3BtreeCommit(). */ { u32 meta; diff --git a/src/vdbe.c b/src/vdbe.c index d965b967..22e6d9c5 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -157,6 +157,13 @@ int sqlite3_found_count = 0; */ #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) +/* Return true if the cursor was opened using the OP_OpenSorter opcode. */ +#ifdef SQLITE_OMIT_MERGE_SORT +# define isSorter(x) 0 +#else +# define isSorter(x) ((x)->pSorter!=0) +#endif + /* ** Argument pMem points at a register that will be passed to a ** user-defined function or returned to the user as the result of a query. @@ -666,7 +673,7 @@ int sqlite3VdbeExec( assert( pOp->p2<=p->nMem ); pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); - sqlite3VdbeMemReleaseExternal(pOut); + MemReleaseExt(pOut); pOut->flags = MEM_Int; } @@ -1027,6 +1034,11 @@ case OP_Move: { zMalloc = pOut->zMalloc; pOut->zMalloc = 0; sqlite3VdbeMemMove(pOut, pIn1); +#ifdef SQLITE_DEBUG + if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){ + pOut->pScopyFrom += p1 - pOp->p2; + } +#endif pIn1->zMalloc = zMalloc; REGISTER_TRACE(p2++, pOut); pIn1++; @@ -2009,6 +2021,16 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ break; } +/* Opcode: Once P1 P2 * * * +** +** Jump to P2 if the value in register P1 is a not null or zero. If +** the value is NULL or zero, fall through and change the P1 register +** to an integer 1. +** +** When P1 is not used otherwise in a program, this opcode falls through +** once and jumps on all subsequent invocations. It is the equivalent +** of "OP_If P1 P2", followed by "OP_Integer 1 P1". +*/ /* Opcode: If P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is true. The value @@ -2021,6 +2043,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ ** is considered true if it has a numeric value of zero. If the value ** in P1 is NULL then take the jump if P3 is true. */ +case OP_Once: /* jump, in1 */ case OP_If: /* jump, in1 */ case OP_IfNot: { /* jump, in1 */ int c; @@ -2037,6 +2060,12 @@ case OP_IfNot: { /* jump, in1 */ } if( c ){ pc = pOp->p2-1; + }else if( pOp->opcode==OP_Once ){ + assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 ); + memAboutToChange(p, pIn1); + pIn1->flags = MEM_Int; + pIn1->u.i = 1; + REGISTER_TRACE(pOp->p1, pIn1); } break; } @@ -2106,6 +2135,7 @@ case OP_Column: { u32 szField; /* Number of bytes in the content of a field */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ + u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ @@ -2117,7 +2147,6 @@ case OP_Column: { assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); - MemSetTypeFlag(pDest, MEM_Null); zRec = 0; /* This block sets the variable payloadSize to be the total number of @@ -2149,7 +2178,7 @@ case OP_Column: { zRec = (char*)pC->aRow; }else if( pC->isIndex ){ assert( sqlite3BtreeCursorIsValid(pCrsr) ); - rc = sqlite3BtreeKeySize(pCrsr, &payloadSize64); + VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64); assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the ** payload size, so it is impossible for payloadSize64 to be @@ -2158,10 +2187,10 @@ case OP_Column: { payloadSize = (u32)payloadSize64; }else{ assert( sqlite3BtreeCursorIsValid(pCrsr) ); - rc = sqlite3BtreeDataSize(pCrsr, &payloadSize); + VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &payloadSize); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ } - }else if( pC->pseudoTableReg>0 ){ + }else if( ALWAYS(pC->pseudoTableReg>0) ){ pReg = &aMem[pC->pseudoTableReg]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); @@ -2174,9 +2203,10 @@ case OP_Column: { payloadSize = 0; } - /* If payloadSize is 0, then just store a NULL */ + /* If payloadSize is 0, then just store a NULL. This can happen because of + ** nullRow or because of a corrupt database. */ if( payloadSize==0 ){ - assert( pDest->flags&MEM_Null ); + MemSetTypeFlag(pDest, MEM_Null); goto op_column_out; } assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 ); @@ -2283,8 +2313,14 @@ case OP_Column: { for(i=0; ip4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ - assert( pDest->flags&MEM_Null ); + MemSetTypeFlag(pDest, MEM_Null); } } @@ -2538,7 +2574,7 @@ case OP_Count: { /* out2-prerelease */ BtCursor *pCrsr; pCrsr = p->apCsr[pOp->p1]->pCursor; - if( pCrsr ){ + if( ALWAYS(pCrsr) ){ rc = sqlite3BtreeCount(pCrsr, &nEntry); }else{ nEntry = 0; @@ -3100,15 +3136,9 @@ case OP_OpenWrite: { rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; - /* Since it performs no memory allocation or IO, the only values that - ** sqlite3BtreeCursor() may return are SQLITE_EMPTY and SQLITE_OK. - ** SQLITE_EMPTY is only returned when attempting to open the table - ** rooted at page 1 of a zero-byte database. */ - assert( rc==SQLITE_EMPTY || rc==SQLITE_OK ); - if( rc==SQLITE_EMPTY ){ - pCur->pCursor = 0; - rc = SQLITE_OK; - } + /* Since it performs no memory allocation or IO, the only value that + ** sqlite3BtreeCursor() may return is SQLITE_OK. */ + assert( rc==SQLITE_OK ); /* Set the VdbeCursor.isTable and isIndex variables. Previous versions of ** SQLite used to check if the root-page flags were sane at this point @@ -3119,7 +3149,7 @@ case OP_OpenWrite: { break; } -/* Opcode: OpenEphemeral P1 P2 * P4 * +/* Opcode: OpenEphemeral P1 P2 * P4 P5 ** ** Open a new cursor P1 to a transient table. ** The cursor is always opened read/write even if @@ -3136,6 +3166,11 @@ case OP_OpenWrite: { ** to a TEMP table at the SQL level, or to a table opened by ** this opcode. Then this opcode was call OpenVirtual. But ** that created confusion with the whole virtual-table idea. +** +** The P5 parameter can be a mask of the BTREE_* flags defined +** in btree.h. These flags control aspects of the operation of +** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are +** added automatically. */ /* Opcode: OpenAutoindex P1 P2 * P4 * ** @@ -3172,7 +3207,7 @@ case OP_OpenEphemeral: { if( pOp->p4.pKeyInfo ){ int pgno; assert( pOp->p4type==P4_KEYINFO ); - rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY); + rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); if( rc==SQLITE_OK ){ assert( pgno==MASTER_ROOT+1 ); rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, @@ -3191,6 +3226,28 @@ case OP_OpenEphemeral: { break; } +/* Opcode: OpenSorter P1 P2 * P4 * +** +** This opcode works like OP_OpenEphemeral except that it opens +** a transient index that is specifically designed to sort large +** tables using an external merge-sort algorithm. +*/ +case OP_SorterOpen: { + VdbeCursor *pCx; +#ifndef SQLITE_OMIT_MERGE_SORT + pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); + if( pCx==0 ) goto no_mem; + pCx->pKeyInfo = pOp->p4.pKeyInfo; + pCx->pKeyInfo->enc = ENC(p->db); + pCx->isSorter = 1; + rc = sqlite3VdbeSorterInit(db, pCx); +#else + pOp->opcode = OP_OpenEphemeral; + pc--; +#endif + break; +} + /* Opcode: OpenPseudo P1 P2 P3 * * ** ** Open a new cursor that points to a fake table that contains a single @@ -3303,7 +3360,7 @@ case OP_SeekGt: { /* jump, in3 */ assert( OP_SeekGe == OP_SeekLt+2 ); assert( OP_SeekGt == OP_SeekLt+3 ); assert( pC->isOrdered ); - if( pC->pCursor!=0 ){ + if( ALWAYS(pC->pCursor!=0) ){ oc = pOp->opcode; pC->nullRow = 0; if( pC->isTable ){ @@ -3491,6 +3548,7 @@ case OP_Found: { /* jump, in3 */ int alreadyExists; VdbeCursor *pC; int res; + char *pFree; UnpackedRecord *pIdxKey; UnpackedRecord r; char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7]; @@ -3518,18 +3576,18 @@ case OP_Found: { /* jump, in3 */ r.flags = UNPACKED_PREFIX_MATCH; pIdxKey = &r; }else{ + pIdxKey = sqlite3VdbeAllocUnpackedRecord( + pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree + ); + if( pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ - pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, - aTempRec, sizeof(aTempRec)); - if( pIdxKey==0 ){ - goto no_mem; - } + sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); pIdxKey->flags |= UNPACKED_PREFIX_MATCH; } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res); if( pOp->p4.i==0 ){ - sqlite3VdbeDeleteUnpackedRecord(pIdxKey); + sqlite3DbFree(db, pFree); } if( rc!=SQLITE_OK ){ break; @@ -3661,7 +3719,7 @@ case OP_NotExists: { /* jump, in3 */ assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; - if( pCrsr!=0 ){ + if( ALWAYS(pCrsr!=0) ){ res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); @@ -4039,6 +4097,45 @@ case OP_ResetCount: { break; } +/* Opcode: SorterCompare P1 P2 P3 +** +** P1 is a sorter cursor. This instruction compares the record blob in +** register P3 with the entry that the sorter cursor currently points to. +** If, excluding the rowid fields at the end, the two records are a match, +** fall through to the next instruction. Otherwise, jump to instruction P2. +*/ +case OP_SorterCompare: { + VdbeCursor *pC; + int res; + + pC = p->apCsr[pOp->p1]; + assert( isSorter(pC) ); + pIn3 = &aMem[pOp->p3]; + rc = sqlite3VdbeSorterCompare(pC, pIn3, &res); + if( res ){ + pc = pOp->p2-1; + } + break; +}; + +/* Opcode: SorterData P1 P2 * * * +** +** Write into register P2 the current sorter data for sorter cursor P1. +*/ +case OP_SorterData: { + VdbeCursor *pC; +#ifndef SQLITE_OMIT_MERGE_SORT + pOut = &aMem[pOp->p2]; + pC = p->apCsr[pOp->p1]; + assert( pC->isSorter ); + rc = sqlite3VdbeSorterRowkey(pC, pOut); +#else + pOp->opcode = OP_RowKey; + pc--; +#endif + break; +} + /* Opcode: RowData P1 P2 * * * ** ** Write into register P2 the complete row data for cursor P1. @@ -4072,11 +4169,13 @@ case OP_RowData: { /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; - assert( pC->isTable || pOp->opcode==OP_RowKey ); + assert( pC->isSorter==0 ); + assert( pC->isTable || pOp->opcode!=OP_RowData ); assert( pC->isIndex || pOp->opcode==OP_RowData ); assert( pC!=0 ); assert( pC->nullRow==0 ); assert( pC->pseudoTableReg==0 ); + assert( !pC->isSorter ); assert( pC->pCursor!=0 ); pCrsr = pC->pCursor; assert( sqlite3BtreeCursorIsValid(pCrsr) ); @@ -4092,14 +4191,14 @@ case OP_RowData: { if( pC->isIndex ){ assert( !pC->isTable ); - rc = sqlite3BtreeKeySize(pCrsr, &n64); + VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64); assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } n = (u32)n64; }else{ - rc = sqlite3BtreeDataSize(pCrsr, &n); + VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; @@ -4181,6 +4280,7 @@ case OP_NullRow: { assert( pC!=0 ); pC->nullRow = 1; pC->rowidIsValid = 0; + assert( pC->pCursor || pC->pVtabCursor ); if( pC->pCursor ){ sqlite3BtreeClearCursor(pC->pCursor); } @@ -4204,9 +4304,8 @@ case OP_Last: { /* jump */ pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pCrsr = pC->pCursor; - if( pCrsr==0 ){ - res = 1; - }else{ + res = 0; + if( ALWAYS(pCrsr!=0) ){ rc = sqlite3BtreeLast(pCrsr, &res); } pC->nullRow = (u8)res; @@ -4232,6 +4331,10 @@ case OP_Last: { /* jump */ ** regression tests can determine whether or not the optimizer is ** correctly optimizing out sorts. */ +case OP_SorterSort: /* jump */ +#ifdef SQLITE_OMIT_MERGE_SORT + pOp->opcode = OP_Sort; +#endif case OP_Sort: { /* jump */ #ifdef SQLITE_TEST sqlite3_sort_count++; @@ -4256,8 +4359,13 @@ case OP_Rewind: { /* jump */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); + assert( pC->isSorter==(pOp->opcode==OP_SorterSort) ); res = 1; - if( (pCrsr = pC->pCursor)!=0 ){ + if( isSorter(pC) ){ + rc = sqlite3VdbeSorterRewind(db, pC, &res); + }else{ + pCrsr = pC->pCursor; + assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0 ?1:0; pC->deferredMoveto = 0; @@ -4272,7 +4380,7 @@ case OP_Rewind: { /* jump */ break; } -/* Opcode: Next P1 P2 * * P5 +/* Opcode: Next P1 P2 * P4 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 @@ -4281,6 +4389,9 @@ case OP_Rewind: { /* jump */ ** ** The P1 cursor must be for a real table, not a pseudo-table. ** +** P4 is always of type P4_ADVANCE. The function pointer points to +** sqlite3BtreeNext(). +** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** @@ -4295,13 +4406,19 @@ case OP_Rewind: { /* jump */ ** ** The P1 cursor must be for a real table, not a pseudo-table. ** +** P4 is always of type P4_ADVANCE. The function pointer points to +** sqlite3BtreePrevious(). +** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ +case OP_SorterNext: /* jump */ +#ifdef SQLITE_OMIT_MERGE_SORT + pOp->opcode = OP_Next; +#endif case OP_Prev: /* jump */ case OP_Next: { /* jump */ VdbeCursor *pC; - BtCursor *pCrsr; int res; CHECK_FOR_INTERRUPT; @@ -4311,15 +4428,18 @@ case OP_Next: { /* jump */ if( pC==0 ){ break; /* See ticket #2273 */ } - pCrsr = pC->pCursor; - if( pCrsr==0 ){ - pC->nullRow = 1; - break; + assert( pC->isSorter==(pOp->opcode==OP_SorterNext) ); + if( isSorter(pC) ){ + assert( pOp->opcode==OP_SorterNext ); + rc = sqlite3VdbeSorterNext(db, pC, &res); + }else{ + res = 1; + assert( pC->deferredMoveto==0 ); + assert( pC->pCursor ); + assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); + assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); + rc = pOp->p4.xAdvance(pC->pCursor, &res); } - res = 1; - assert( pC->deferredMoveto==0 ); - rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : - sqlite3BtreePrevious(pCrsr, &res); pC->nullRow = (u8)res; pC->cacheStatus = CACHE_STALE; if( res==0 ){ @@ -4345,6 +4465,10 @@ case OP_Next: { /* jump */ ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ +case OP_SorterInsert: /* in2 */ +#ifdef SQLITE_OMIT_MERGE_SORT + pOp->opcode = OP_IdxInsert; +#endif case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; BtCursor *pCrsr; @@ -4354,6 +4478,7 @@ case OP_IdxInsert: { /* in2 */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); + assert( pC->isSorter==(pOp->opcode==OP_SorterInsert) ); pIn2 = &aMem[pOp->p2]; assert( pIn2->flags & MEM_Blob ); pCrsr = pC->pCursor; @@ -4361,13 +4486,17 @@ case OP_IdxInsert: { /* in2 */ assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc==SQLITE_OK ){ - nKey = pIn2->n; - zKey = pIn2->z; - rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3, - ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) - ); - assert( pC->deferredMoveto==0 ); - pC->cacheStatus = CACHE_STALE; + if( isSorter(pC) ){ + rc = sqlite3VdbeSorterWrite(db, pC, pIn2); + }else{ + nKey = pIn2->n; + zKey = pIn2->z; + rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3, + ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) + ); + assert( pC->deferredMoveto==0 ); + pC->cacheStatus = CACHE_STALE; + } } } break; @@ -5337,7 +5466,7 @@ case OP_JournalMode: { /* out2-prerelease */ ** in temporary storage or if the VFS does not support shared memory */ if( eNew==PAGER_JOURNALMODE_WAL - && (zFilename[0]==0 /* Temp file */ + && (sqlite3Strlen30(zFilename)==0 /* Temp file */ || !sqlite3PagerWalSupported(pPager)) /* No shared-memory support */ ){ eNew = eOld; @@ -5758,10 +5887,15 @@ case OP_VRename: { assert( memIsValid(pName) ); REGISTER_TRACE(pOp->p1, pName); assert( pName->flags & MEM_Str ); - rc = pVtab->pModule->xRename(pVtab, pName->z); - importVtabErrMsg(p, pVtab); - p->expired = 0; - + testcase( pName->enc==SQLITE_UTF8 ); + testcase( pName->enc==SQLITE_UTF16BE ); + testcase( pName->enc==SQLITE_UTF16LE ); + rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); + if( rc==SQLITE_OK ){ + rc = pVtab->pModule->xRename(pVtab, pName->z); + importVtabErrMsg(p, pVtab); + p->expired = 0; + } break; } #endif diff --git a/src/vdbe.h b/src/vdbe.h index e66ee302..948c73bc 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -61,6 +61,7 @@ struct VdbeOp { KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ + int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_DEBUG char *zComment; /* Comment to improve readability */ @@ -116,6 +117,7 @@ typedef struct VdbeOpList VdbeOpList; #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ +#define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the @@ -173,12 +175,12 @@ int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); -void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); -void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); -void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); +void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); +void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); +void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u8 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); -void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); +void sqlite3VdbeChangeToNoop(Vdbe*, int addr); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); @@ -210,9 +212,9 @@ void sqlite3VdbeSetVarmask(Vdbe*, int); char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif -UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int); -void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*); +void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); +UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); #ifndef SQLITE_OMIT_TRIGGER void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 0aeb3af7..803ae163 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -30,6 +30,9 @@ typedef struct VdbeOp Op; */ typedef unsigned char Bool; +/* Opaque type used by code in vdbesort.c */ +typedef struct VdbeSorter VdbeSorter; + /* ** A cursor is a pointer into a single BTree within a database file. ** The cursor can seek to a BTree entry with a particular key, or @@ -56,11 +59,13 @@ struct VdbeCursor { Bool isTable; /* True if a table requiring integer keys */ Bool isIndex; /* True if an index containing keys only - no data */ Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */ + Bool isSorter; /* True if a new-style sorter */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ + VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or ** OP_IsUnique opcode on this cursor. */ @@ -380,6 +385,9 @@ int sqlite3VdbeMemNumerify(Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); void sqlite3VdbeMemReleaseExternal(Mem *p); +#define MemReleaseExt(X) \ + if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \ + sqlite3VdbeMemReleaseExternal(X); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); @@ -387,6 +395,25 @@ int sqlite3VdbeCloseStatement(Vdbe *, int); void sqlite3VdbeFrameDelete(VdbeFrame*); int sqlite3VdbeFrameRestore(VdbeFrame *); void sqlite3VdbeMemStoreType(Mem *pMem); +int sqlite3VdbeTransferError(Vdbe *p); + +#ifdef SQLITE_OMIT_MERGE_SORT +# define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK +# define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK +# define sqlite3VdbeSorterClose(Y,Z) +# define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK +# define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK +# define sqlite3VdbeSorterNext(X,Y,Z) SQLITE_OK +# define sqlite3VdbeSorterCompare(X,Y,Z) SQLITE_OK +#else +int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); +void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); +int sqlite3VdbeSorterRowkey(VdbeCursor *, Mem *); +int sqlite3VdbeSorterNext(sqlite3 *, VdbeCursor *, int *); +int sqlite3VdbeSorterRewind(sqlite3 *, VdbeCursor *, int *); +int sqlite3VdbeSorterWrite(sqlite3 *, VdbeCursor *, Mem *); +int sqlite3VdbeSorterCompare(VdbeCursor *, Mem *, int *); +#endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 void sqlite3VdbeEnter(Vdbe*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index a87b5c9a..adc9dba2 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -454,7 +454,7 @@ end_of_step: ** error has occured, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ - rc = db->errCode = p->rc; + rc = sqlite3VdbeTransferError(p); } return (rc&db->errMask); } @@ -488,7 +488,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){ && cnt++ < SQLITE_MAX_SCHEMA_RETRY && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){ sqlite3_reset(pStmt); - v->expired = 0; + assert( v->expired==0 ); } if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){ /* This case occurs after failing to recompile an sql statement. diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 989a8003..75250238 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -433,6 +433,12 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; #endif + }else if( opcode==OP_Next || opcode==OP_SorterNext ){ + pOp->p4.xAdvance = sqlite3BtreeNext; + pOp->p4type = P4_ADVANCE; + }else if( opcode==OP_Prev ){ + pOp->p4.xAdvance = sqlite3BtreePrevious; + pOp->p4type = P4_ADVANCE; } if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ @@ -524,10 +530,9 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ ** static array using sqlite3VdbeAddOpList but we want to make a ** few minor changes to the program. */ -void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ +void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){ assert( p!=0 ); - assert( addr>=0 ); - if( p->nOp>addr ){ + if( ((u32)p->nOp)>addr ){ p->aOp[addr].p1 = val; } } @@ -536,10 +541,9 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ ** Change the value of the P2 operand for a specific instruction. ** This routine is useful for setting a jump destination. */ -void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ +void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){ assert( p!=0 ); - assert( addr>=0 ); - if( p->nOp>addr ){ + if( ((u32)p->nOp)>addr ){ p->aOp[addr].p2 = val; } } @@ -547,10 +551,9 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ /* ** Change the value of the P3 operand for a specific instruction. */ -void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){ +void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){ assert( p!=0 ); - assert( addr>=0 ); - if( p->nOp>addr ){ + if( ((u32)p->nOp)>addr ){ p->aOp[addr].p3 = val; } } @@ -572,8 +575,8 @@ void sqlite3VdbeChangeP5(Vdbe *p, u8 val){ ** the address of the next instruction to be coded. */ void sqlite3VdbeJumpHere(Vdbe *p, int addr){ - assert( addr>=0 ); - sqlite3VdbeChangeP2(p, addr, p->nOp); + assert( addr>=0 || p->db->mallocFailed ); + if( addr>=0 ) sqlite3VdbeChangeP2(p, addr, p->nOp); } @@ -667,18 +670,15 @@ void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ } /* -** Change N opcodes starting at addr to No-ops. +** Change the opcode at addr into OP_Noop */ -void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){ +void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ if( p->aOp ){ VdbeOp *pOp = &p->aOp[addr]; sqlite3 *db = p->db; - while( N-- ){ - freeP4(db, pOp->p4type, pOp->p4.p); - memset(pOp, 0, sizeof(pOp[0])); - pOp->opcode = OP_Noop; - pOp++; - } + freeP4(db, pOp->p4type, pOp->p4.p); + memset(pOp, 0, sizeof(pOp[0])); + pOp->opcode = OP_Noop; } } @@ -781,30 +781,29 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ ** makes the code easier to read during debugging. None of this happens ** in a production build. */ -void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ - va_list ap; - if( !p ) return; +static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ assert( p->nOp>0 || p->aOp==0 ); assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); if( p->nOp ){ - char **pz = &p->aOp[p->nOp-1].zComment; + assert( p->aOp ); + sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment); + p->aOp[p->nOp-1].zComment = sqlite3VMPrintf(p->db, zFormat, ap); + } +} +void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ + va_list ap; + if( p ){ va_start(ap, zFormat); - sqlite3DbFree(p->db, *pz); - *pz = sqlite3VMPrintf(p->db, zFormat, ap); + vdbeVComment(p, zFormat, ap); va_end(ap); } } void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){ va_list ap; - if( !p ) return; - sqlite3VdbeAddOp0(p, OP_Noop); - assert( p->nOp>0 || p->aOp==0 ); - assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); - if( p->nOp ){ - char **pz = &p->aOp[p->nOp-1].zComment; + if( p ){ + sqlite3VdbeAddOp0(p, OP_Noop); va_start(ap, zFormat); - sqlite3DbFree(p->db, *pz); - *pz = sqlite3VMPrintf(p->db, zFormat, ap); + vdbeVComment(p, zFormat, ap); va_end(ap); } } @@ -834,7 +833,7 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ /* 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 */ + static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ assert( p->magic==VDBE_MAGIC_INIT ); if( addr<0 ){ #ifdef SQLITE_OMIT_TRACE @@ -942,6 +941,10 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ sqlite3_snprintf(nTemp, zTemp, "program"); break; } + case P4_ADVANCE: { + zTemp[0] = 0; + break; + } default: { zP4 = pOp->p4.z; if( zP4==0 ){ @@ -1138,7 +1141,7 @@ int sqlite3VdbeList( sqlite3 *db = p->db; /* The database connection */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ - Mem *pMem = p->pResultSet = &p->aMem[1]; /* First Mem of result set */ + Mem *pMem = &p->aMem[1]; /* First Mem of result set */ assert( p->explain ); assert( p->magic==VDBE_MAGIC_RUN ); @@ -1149,6 +1152,7 @@ int sqlite3VdbeList( ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ releaseMemArray(pMem, 8); + p->pResultSet = 0; if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or @@ -1303,6 +1307,7 @@ int sqlite3VdbeList( } p->nResColumn = 8 - 4*(p->explain-1); + p->pResultSet = &p->aMem[1]; p->rc = SQLITE_OK; rc = SQLITE_ROW; } @@ -1565,6 +1570,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx==0 ){ return; } + sqlite3VdbeSorterClose(p->db, pCx); if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); /* The pCx->pCursor will be close automatically, if it exists, by @@ -2304,6 +2310,30 @@ void sqlite3VdbeResetStepResult(Vdbe *p){ p->rc = SQLITE_OK; } +/* +** Copy the error code and error message belonging to the VDBE passed +** as the first argument to its database handle (so that they will be +** returned by calls to sqlite3_errcode() and sqlite3_errmsg()). +** +** This function does not clear the VDBE error code or message, just +** copies them to the database handle. +*/ +int sqlite3VdbeTransferError(Vdbe *p){ + sqlite3 *db = p->db; + int rc = p->rc; + if( p->zErrMsg ){ + u8 mallocFailed = db->mallocFailed; + sqlite3BeginBenignMalloc(); + sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); + sqlite3EndBenignMalloc(); + db->mallocFailed = mallocFailed; + db->errCode = rc; + }else{ + sqlite3Error(db, rc, 0); + } + return rc; +} + /* ** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Write any error messages into *pzErrMsg. Return the result code. @@ -2331,18 +2361,9 @@ int sqlite3VdbeReset(Vdbe *p){ ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ - if( p->zErrMsg ){ - sqlite3BeginBenignMalloc(); - sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,SQLITE_TRANSIENT); - sqlite3EndBenignMalloc(); - db->errCode = p->rc; - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; - }else if( p->rc ){ - sqlite3Error(db, p->rc, 0); - }else{ - sqlite3Error(db, SQLITE_OK, 0); - } + sqlite3VdbeTransferError(p); + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = 0; if( p->runOnlyOnce ) p->expired = 1; }else if( p->rc && p->expired ){ /* The expired flag was set on the VDBE before the first call @@ -2822,57 +2843,70 @@ u32 sqlite3VdbeSerialGet( return 0; } - /* -** Given the nKey-byte encoding of a record in pKey[], parse the -** record into a UnpackedRecord structure. Return a pointer to -** that structure. +** This routine is used to allocate sufficient space for an UnpackedRecord +** structure large enough to be used with sqlite3VdbeRecordUnpack() if +** the first argument is a pointer to KeyInfo structure pKeyInfo. ** -** The calling function might provide szSpace bytes of memory -** space at pSpace. This space can be used to hold the returned -** VDbeParsedRecord structure if it is large enough. If it is -** not big enough, space is obtained from sqlite3_malloc(). +** The space is either allocated using sqlite3DbMallocRaw() or from within +** the unaligned buffer passed via the second and third arguments (presumably +** stack space). If the former, then *ppFree is set to a pointer that should +** be eventually freed by the caller using sqlite3DbFree(). Or, if the +** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL +** before returning. ** -** The returned structure should be closed by a call to -** sqlite3VdbeDeleteUnpackedRecord(). -*/ -UnpackedRecord *sqlite3VdbeRecordUnpack( - KeyInfo *pKeyInfo, /* Information about the record format */ - int nKey, /* Size of the binary record */ - const void *pKey, /* The binary record */ - char *pSpace, /* Unaligned space available to hold the object */ - int szSpace /* Size of pSpace[] in bytes */ +** If an OOM error occurs, NULL is returned. +*/ +UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( + KeyInfo *pKeyInfo, /* Description of the record */ + char *pSpace, /* Unaligned space available */ + int szSpace, /* Size of pSpace[] in bytes */ + char **ppFree /* OUT: Caller should free this pointer */ ){ - const unsigned char *aKey = (const unsigned char *)pKey; - UnpackedRecord *p; /* The unpacked record that we will return */ - int nByte; /* Memory space needed to hold p, in bytes */ - int d; - u32 idx; - u16 u; /* Unsigned loop counter */ - u32 szHdr; - Mem *pMem; - int nOff; /* Increase pSpace by this much to 8-byte align it */ - - /* - ** We want to shift the pointer pSpace up such that it is 8-byte aligned. + UnpackedRecord *p; /* Unpacked record to return */ + int nOff; /* Increment pSpace by nOff to align it */ + int nByte; /* Number of bytes required for *p */ + + /* We want to shift the pointer pSpace up such that it is 8-byte aligned. ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift ** it by. If pSpace is already 8-byte aligned, nOff should be zero. */ nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7; - pSpace += nOff; - szSpace -= nOff; nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1); - if( nByte>szSpace ){ - p = sqlite3DbMallocRaw(pKeyInfo->db, nByte); - if( p==0 ) return 0; - p->flags = UNPACKED_NEED_FREE | UNPACKED_NEED_DESTROY; + if( nByte>szSpace+nOff ){ + p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); + *ppFree = (char *)p; + if( !p ) return 0; }else{ - p = (UnpackedRecord*)pSpace; - p->flags = UNPACKED_NEED_DESTROY; + p = (UnpackedRecord*)&pSpace[nOff]; + *ppFree = 0; } + + p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nField + 1; - p->aMem = pMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; + return p; +} + +/* +** Given the nKey-byte encoding of a record in pKey[], populate the +** UnpackedRecord structure indicated by the fourth argument with the +** contents of the decoded record. +*/ +void sqlite3VdbeRecordUnpack( + KeyInfo *pKeyInfo, /* Information about the record format */ + int nKey, /* Size of the binary record */ + const void *pKey, /* The binary record */ + UnpackedRecord *p /* Populate this structure before returning. */ +){ + const unsigned char *aKey = (const unsigned char *)pKey; + int d; + u32 idx; /* Offset in aKey[] to read from */ + u16 u; /* Unsigned loop counter */ + u32 szHdr; + Mem *pMem = p->aMem; + + p->flags = 0; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); idx = getVarint32(aKey, szHdr); d = szHdr; @@ -2891,31 +2925,6 @@ UnpackedRecord *sqlite3VdbeRecordUnpack( } assert( u<=pKeyInfo->nField + 1 ); p->nField = u; - return (void*)p; -} - -/* -** This routine destroys a UnpackedRecord object. -*/ -void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ -#ifdef SQLITE_DEBUG - int i; - Mem *pMem; - - assert( p!=0 ); - assert( p->flags & UNPACKED_NEED_DESTROY ); - for(i=0, pMem=p->aMem; inField; i++, pMem++){ - /* The unpacked record is always constructed by the - ** sqlite3VdbeUnpackRecord() function above, which makes all - ** strings and blobs static. And none of the elements are - ** ever transformed, so there is never anything to delete. - */ - if( NEVER(pMem->zMalloc) ) sqlite3VdbeMemRelease(pMem); - } -#endif - if( p->flags & UNPACKED_NEED_FREE ){ - sqlite3DbFree(p->pKeyInfo->db, p); - } } /* @@ -3069,7 +3078,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); - rc = sqlite3BtreeKeySize(pCur, &nCellKey); + VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); @@ -3144,7 +3153,7 @@ int sqlite3VdbeIdxKeyCompare( Mem m; assert( sqlite3BtreeCursorIsValid(pCur) ); - rc = sqlite3BtreeKeySize(pCur, &nCellKey); + VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ /* nCellKey will always be between 0 and 0xffffffff because of the say ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ diff --git a/src/vdbeblob.c b/src/vdbeblob.c index a8728e6d..ae77a47b 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -273,7 +273,7 @@ int sqlite3_blob_open( /* Configure the OP_TableLock instruction */ #ifdef SQLITE_OMIT_SHARED_CACHE - sqlite3VdbeChangeToNoop(v, 2, 1); + sqlite3VdbeChangeToNoop(v, 2); #else sqlite3VdbeChangeP1(v, 2, iDb); sqlite3VdbeChangeP2(v, 2, pTab->tnum); @@ -283,7 +283,7 @@ int sqlite3_blob_open( /* Remove either the OP_OpenWrite or OpenRead. Set the P2 ** parameter of the other to pTab->tnum. */ - sqlite3VdbeChangeToNoop(v, 4 - flags, 1); + sqlite3VdbeChangeToNoop(v, 4 - flags); sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum); sqlite3VdbeChangeP3(v, 3 + flags, iDb); diff --git a/src/vdbemem.c b/src/vdbemem.c index 882c6863..e6e91562 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -271,24 +271,18 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ */ void sqlite3VdbeMemReleaseExternal(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); - testcase( p->flags & MEM_Agg ); - testcase( p->flags & MEM_Dyn ); - testcase( p->flags & MEM_RowSet ); - testcase( p->flags & MEM_Frame ); - if( p->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame) ){ - if( p->flags&MEM_Agg ){ - sqlite3VdbeMemFinalize(p, p->u.pDef); - assert( (p->flags & MEM_Agg)==0 ); - sqlite3VdbeMemRelease(p); - }else if( p->flags&MEM_Dyn && p->xDel ){ - assert( (p->flags&MEM_RowSet)==0 ); - p->xDel((void *)p->z); - p->xDel = 0; - }else if( p->flags&MEM_RowSet ){ - sqlite3RowSetClear(p->u.pRowSet); - }else if( p->flags&MEM_Frame ){ - sqlite3VdbeMemSetNull(p); - } + if( p->flags&MEM_Agg ){ + sqlite3VdbeMemFinalize(p, p->u.pDef); + assert( (p->flags & MEM_Agg)==0 ); + sqlite3VdbeMemRelease(p); + }else if( p->flags&MEM_Dyn && p->xDel ){ + assert( (p->flags&MEM_RowSet)==0 ); + p->xDel((void *)p->z); + p->xDel = 0; + }else if( p->flags&MEM_RowSet ){ + sqlite3RowSetClear(p->u.pRowSet); + }else if( p->flags&MEM_Frame ){ + sqlite3VdbeMemSetNull(p); } } @@ -298,7 +292,7 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){ ** (Mem.type==SQLITE_TEXT). */ void sqlite3VdbeMemRelease(Mem *p){ - sqlite3VdbeMemReleaseExternal(p); + MemReleaseExt(p); sqlite3DbFree(p->db, p->zMalloc); p->z = 0; p->zMalloc = 0; @@ -620,7 +614,7 @@ void sqlite3VdbeMemPrepareToChange(Vdbe *pVdbe, Mem *pMem){ */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ assert( (pFrom->flags & MEM_RowSet)==0 ); - sqlite3VdbeMemReleaseExternal(pTo); + MemReleaseExt(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->xDel = 0; if( (pFrom->flags&MEM_Static)==0 ){ @@ -638,7 +632,7 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; assert( (pFrom->flags & MEM_RowSet)==0 ); - sqlite3VdbeMemReleaseExternal(pTo); + MemReleaseExt(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; @@ -1032,11 +1026,11 @@ int sqlite3ValueFromExpr( } op = pExpr->op; - /* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT2. + /* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT3. ** The ifdef here is to enable us to achieve 100% branch test coverage even - ** when SQLITE_ENABLE_STAT2 is omitted. + ** when SQLITE_ENABLE_STAT3 is omitted. */ -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 if( op==TK_REGISTER ) op = pExpr->op2; #else if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; diff --git a/src/vdbesort.c b/src/vdbesort.c new file mode 100644 index 00000000..c4499970 --- /dev/null +++ b/src/vdbesort.c @@ -0,0 +1,882 @@ +/* +** 2011 July 9 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains code for the VdbeSorter object, used in concert with +** a VdbeCursor to sort large numbers of keys (as may be required, for +** example, by CREATE INDEX statements on tables too large to fit in main +** memory). +*/ + +#include "sqliteInt.h" +#include "vdbeInt.h" + +#ifndef SQLITE_OMIT_MERGE_SORT + +typedef struct VdbeSorterIter VdbeSorterIter; +typedef struct SorterRecord SorterRecord; + +/* +** NOTES ON DATA STRUCTURE USED FOR N-WAY MERGES: +** +** As keys are added to the sorter, they are written to disk in a series +** of sorted packed-memory-arrays (PMAs). The size of each PMA is roughly +** the same as the cache-size allowed for temporary databases. In order +** to allow the caller to extract keys from the sorter in sorted order, +** all PMAs currently stored on disk must be merged together. This comment +** describes the data structure used to do so. The structure supports +** merging any number of arrays in a single pass with no redundant comparison +** operations. +** +** The aIter[] array contains an iterator for each of the PMAs being merged. +** An aIter[] iterator either points to a valid key or else is at EOF. For +** the purposes of the paragraphs below, we assume that the array is actually +** N elements in size, where N is the smallest power of 2 greater to or equal +** to the number of iterators being merged. The extra aIter[] elements are +** treated as if they are empty (always at EOF). +** +** The aTree[] array is also N elements in size. The value of N is stored in +** the VdbeSorter.nTree variable. +** +** The final (N/2) elements of aTree[] contain the results of comparing +** pairs of iterator keys together. Element i contains the result of +** comparing aIter[2*i-N] and aIter[2*i-N+1]. Whichever key is smaller, the +** aTree element is set to the index of it. +** +** For the purposes of this comparison, EOF is considered greater than any +** other key value. If the keys are equal (only possible with two EOF +** values), it doesn't matter which index is stored. +** +** The (N/4) elements of aTree[] that preceed the final (N/2) described +** above contains the index of the smallest of each block of 4 iterators. +** And so on. So that aTree[1] contains the index of the iterator that +** currently points to the smallest key value. aTree[0] is unused. +** +** Example: +** +** aIter[0] -> Banana +** aIter[1] -> Feijoa +** aIter[2] -> Elderberry +** aIter[3] -> Currant +** aIter[4] -> Grapefruit +** aIter[5] -> Apple +** aIter[6] -> Durian +** aIter[7] -> EOF +** +** aTree[] = { X, 5 0, 5 0, 3, 5, 6 } +** +** The current element is "Apple" (the value of the key indicated by +** iterator 5). When the Next() operation is invoked, iterator 5 will +** be advanced to the next key in its segment. Say the next key is +** "Eggplant": +** +** aIter[5] -> Eggplant +** +** The contents of aTree[] are updated first by comparing the new iterator +** 5 key to the current key of iterator 4 (still "Grapefruit"). The iterator +** 5 value is still smaller, so aTree[6] is set to 5. And so on up the tree. +** The value of iterator 6 - "Durian" - is now smaller than that of iterator +** 5, so aTree[3] is set to 6. Key 0 is smaller than key 6 (BananaaAlloc); + memset(pIter, 0, sizeof(VdbeSorterIter)); +} + +/* +** Advance iterator pIter to the next key in its PMA. Return SQLITE_OK if +** no error occurs, or an SQLite error code if one does. +*/ +static int vdbeSorterIterNext( + sqlite3 *db, /* Database handle (for sqlite3DbMalloc() ) */ + VdbeSorterIter *pIter /* Iterator to advance */ +){ + int rc; /* Return Code */ + int nRead; /* Number of bytes read */ + int nRec = 0; /* Size of record in bytes */ + int iOff = 0; /* Size of serialized size varint in bytes */ + + assert( pIter->iEof>=pIter->iReadOff ); + if( pIter->iEof-pIter->iReadOff>5 ){ + nRead = 5; + }else{ + nRead = (int)(pIter->iEof - pIter->iReadOff); + } + if( nRead<=0 ){ + /* This is an EOF condition */ + vdbeSorterIterZero(db, pIter); + return SQLITE_OK; + } + + rc = sqlite3OsRead(pIter->pFile, pIter->aAlloc, nRead, pIter->iReadOff); + if( rc==SQLITE_OK ){ + iOff = getVarint32(pIter->aAlloc, nRec); + if( (iOff+nRec)>nRead ){ + int nRead2; /* Number of extra bytes to read */ + if( (iOff+nRec)>pIter->nAlloc ){ + int nNew = pIter->nAlloc*2; + while( (iOff+nRec)>nNew ) nNew = nNew*2; + pIter->aAlloc = sqlite3DbReallocOrFree(db, pIter->aAlloc, nNew); + if( !pIter->aAlloc ) return SQLITE_NOMEM; + pIter->nAlloc = nNew; + } + + nRead2 = iOff + nRec - nRead; + rc = sqlite3OsRead( + pIter->pFile, &pIter->aAlloc[nRead], nRead2, pIter->iReadOff+nRead + ); + } + } + + assert( rc!=SQLITE_OK || nRec>0 ); + pIter->iReadOff += iOff+nRec; + pIter->nKey = nRec; + pIter->aKey = &pIter->aAlloc[iOff]; + return rc; +} + +/* +** Write a single varint, value iVal, to file-descriptor pFile. Return +** SQLITE_OK if successful, or an SQLite error code if some error occurs. +** +** The value of *piOffset when this function is called is used as the byte +** offset in file pFile to write to. Before returning, *piOffset is +** incremented by the number of bytes written. +*/ +static int vdbeSorterWriteVarint( + sqlite3_file *pFile, /* File to write to */ + i64 iVal, /* Value to write as a varint */ + i64 *piOffset /* IN/OUT: Write offset in file pFile */ +){ + u8 aVarint[9]; /* Buffer large enough for a varint */ + int nVarint; /* Number of used bytes in varint */ + int rc; /* Result of write() call */ + + nVarint = sqlite3PutVarint(aVarint, iVal); + rc = sqlite3OsWrite(pFile, aVarint, nVarint, *piOffset); + *piOffset += nVarint; + + return rc; +} + +/* +** Read a single varint from file-descriptor pFile. Return SQLITE_OK if +** successful, or an SQLite error code if some error occurs. +** +** The value of *piOffset when this function is called is used as the +** byte offset in file pFile from whence to read the varint. If successful +** (i.e. if no IO error occurs), then *piOffset is set to the offset of +** the first byte past the end of the varint before returning. *piVal is +** set to the integer value read. If an error occurs, the final values of +** both *piOffset and *piVal are undefined. +*/ +static int vdbeSorterReadVarint( + sqlite3_file *pFile, /* File to read from */ + i64 *piOffset, /* IN/OUT: Read offset in pFile */ + i64 *piVal /* OUT: Value read from file */ +){ + u8 aVarint[9]; /* Buffer large enough for a varint */ + i64 iOff = *piOffset; /* Offset in file to read from */ + int rc; /* Return code */ + + rc = sqlite3OsRead(pFile, aVarint, 9, iOff); + if( rc==SQLITE_OK ){ + *piOffset += getVarint(aVarint, (u64 *)piVal); + } + + return rc; +} + +/* +** Initialize iterator pIter to scan through the PMA stored in file pFile +** starting at offset iStart and ending at offset iEof-1. This function +** leaves the iterator pointing to the first key in the PMA (or EOF if the +** PMA is empty). +*/ +static int vdbeSorterIterInit( + sqlite3 *db, /* Database handle */ + VdbeSorter *pSorter, /* Sorter object */ + i64 iStart, /* Start offset in pFile */ + VdbeSorterIter *pIter, /* Iterator to populate */ + i64 *pnByte /* IN/OUT: Increment this value by PMA size */ +){ + int rc; + + assert( pSorter->iWriteOff>iStart ); + assert( pIter->aAlloc==0 ); + pIter->pFile = pSorter->pTemp1; + pIter->iReadOff = iStart; + pIter->nAlloc = 128; + pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc); + if( !pIter->aAlloc ){ + rc = SQLITE_NOMEM; + }else{ + i64 nByte; /* Total size of PMA in bytes */ + rc = vdbeSorterReadVarint(pSorter->pTemp1, &pIter->iReadOff, &nByte); + *pnByte += nByte; + pIter->iEof = pIter->iReadOff + nByte; + } + if( rc==SQLITE_OK ){ + rc = vdbeSorterIterNext(db, pIter); + } + return rc; +} + + +/* +** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, +** size nKey2 bytes). Argument pKeyInfo supplies the collation functions +** used by the comparison. If an error occurs, return an SQLite error code. +** Otherwise, return SQLITE_OK and set *pRes to a negative, zero or positive +** value, depending on whether key1 is smaller, equal to or larger than key2. +** +** If the bOmitRowid argument is non-zero, assume both keys end in a rowid +** field. For the purposes of the comparison, ignore it. Also, if bOmitRowid +** is true and key1 contains even a single NULL value, it is considered to +** be less than key2. Even if key2 also contains NULL values. +** +** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace +** has been allocated and contains an unpacked record that is used as key2. +*/ +static void vdbeSorterCompare( + VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ + int bOmitRowid, /* Ignore rowid field at end of keys */ + void *pKey1, int nKey1, /* Left side of comparison */ + void *pKey2, int nKey2, /* Right side of comparison */ + int *pRes /* OUT: Result of comparison */ +){ + KeyInfo *pKeyInfo = pCsr->pKeyInfo; + VdbeSorter *pSorter = pCsr->pSorter; + UnpackedRecord *r2 = pSorter->pUnpacked; + int i; + + if( pKey2 ){ + sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); + } + + if( bOmitRowid ){ + r2->nField = pKeyInfo->nField; + assert( r2->nField>0 ); + for(i=0; inField; i++){ + if( r2->aMem[i].flags & MEM_Null ){ + *pRes = -1; + return; + } + } + r2->flags |= UNPACKED_PREFIX_MATCH; + } + + *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2); +} + +/* +** This function is called to compare two iterator keys when merging +** multiple b-tree segments. Parameter iOut is the index of the aTree[] +** value to recalculate. +*/ +static int vdbeSorterDoCompare(VdbeCursor *pCsr, int iOut){ + VdbeSorter *pSorter = pCsr->pSorter; + int i1; + int i2; + int iRes; + VdbeSorterIter *p1; + VdbeSorterIter *p2; + + assert( iOutnTree && iOut>0 ); + + if( iOut>=(pSorter->nTree/2) ){ + i1 = (iOut - pSorter->nTree/2) * 2; + i2 = i1 + 1; + }else{ + i1 = pSorter->aTree[iOut*2]; + i2 = pSorter->aTree[iOut*2+1]; + } + + p1 = &pSorter->aIter[i1]; + p2 = &pSorter->aIter[i2]; + + if( p1->pFile==0 ){ + iRes = i2; + }else if( p2->pFile==0 ){ + iRes = i1; + }else{ + int res; + assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */ + vdbeSorterCompare( + pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res + ); + if( res<=0 ){ + iRes = i1; + }else{ + iRes = i2; + } + } + + pSorter->aTree[iOut] = iRes; + return SQLITE_OK; +} + +/* +** Initialize the temporary index cursor just opened as a sorter cursor. +*/ +int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){ + int pgsz; /* Page size of main database */ + int mxCache; /* Cache size */ + VdbeSorter *pSorter; /* The new sorter */ + char *d; /* Dummy */ + + assert( pCsr->pKeyInfo && pCsr->pBt==0 ); + pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter)); + if( pSorter==0 ){ + return SQLITE_NOMEM; + } + + pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo, 0, 0, &d); + if( pSorter->pUnpacked==0 ) return SQLITE_NOMEM; + assert( pSorter->pUnpacked==(UnpackedRecord *)d ); + + if( !sqlite3TempInMemory(db) ){ + pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); + pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; + mxCache = db->aDb[0].pSchema->cache_size; + if( mxCachemxPmaSize = mxCache * pgsz; + } + + return SQLITE_OK; +} + +/* +** Free the list of sorted records starting at pRecord. +*/ +static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ + SorterRecord *p; + SorterRecord *pNext; + for(p=pRecord; p; p=pNext){ + pNext = p->pNext; + sqlite3DbFree(db, p); + } +} + +/* +** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. +*/ +void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ + VdbeSorter *pSorter = pCsr->pSorter; + if( pSorter ){ + if( pSorter->aIter ){ + int i; + for(i=0; inTree; i++){ + vdbeSorterIterZero(db, &pSorter->aIter[i]); + } + sqlite3DbFree(db, pSorter->aIter); + } + if( pSorter->pTemp1 ){ + sqlite3OsCloseFree(pSorter->pTemp1); + } + vdbeSorterRecordFree(db, pSorter->pRecord); + sqlite3DbFree(db, pSorter->pUnpacked); + sqlite3DbFree(db, pSorter); + pCsr->pSorter = 0; + } +} + +/* +** Allocate space for a file-handle and open a temporary file. If successful, +** set *ppFile to point to the malloc'd file-handle and return SQLITE_OK. +** Otherwise, set *ppFile to 0 and return an SQLite error code. +*/ +static int vdbeSorterOpenTempFile(sqlite3 *db, sqlite3_file **ppFile){ + int dummy; + return sqlite3OsOpenMalloc(db->pVfs, 0, ppFile, + SQLITE_OPEN_TEMP_JOURNAL | + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &dummy + ); +} + +/* +** Merge the two sorted lists p1 and p2 into a single list. +** Set *ppOut to the head of the new list. +*/ +static void vdbeSorterMerge( + VdbeCursor *pCsr, /* For pKeyInfo */ + SorterRecord *p1, /* First list to merge */ + SorterRecord *p2, /* Second list to merge */ + SorterRecord **ppOut /* OUT: Head of merged list */ +){ + SorterRecord *pFinal = 0; + SorterRecord **pp = &pFinal; + void *pVal2 = p2 ? p2->pVal : 0; + + while( p1 && p2 ){ + int res; + vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res); + if( res<=0 ){ + *pp = p1; + pp = &p1->pNext; + p1 = p1->pNext; + pVal2 = 0; + }else{ + *pp = p2; + pp = &p2->pNext; + p2 = p2->pNext; + if( p2==0 ) break; + pVal2 = p2->pVal; + } + } + *pp = p1 ? p1 : p2; + *ppOut = pFinal; +} + +/* +** Sort the linked list of records headed at pCsr->pRecord. Return SQLITE_OK +** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error +** occurs. +*/ +static int vdbeSorterSort(VdbeCursor *pCsr){ + int i; + SorterRecord **aSlot; + SorterRecord *p; + VdbeSorter *pSorter = pCsr->pSorter; + + aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); + if( !aSlot ){ + return SQLITE_NOMEM; + } + + p = pSorter->pRecord; + while( p ){ + SorterRecord *pNext = p->pNext; + p->pNext = 0; + for(i=0; aSlot[i]; i++){ + vdbeSorterMerge(pCsr, p, aSlot[i], &p); + aSlot[i] = 0; + } + aSlot[i] = p; + p = pNext; + } + + p = 0; + for(i=0; i<64; i++){ + vdbeSorterMerge(pCsr, p, aSlot[i], &p); + } + pSorter->pRecord = p; + + sqlite3_free(aSlot); + return SQLITE_OK; +} + + +/* +** Write the current contents of the in-memory linked-list to a PMA. Return +** SQLITE_OK if successful, or an SQLite error code otherwise. +** +** The format of a PMA is: +** +** * A varint. This varint contains the total number of bytes of content +** in the PMA (not including the varint itself). +** +** * One or more records packed end-to-end in order of ascending keys. +** Each record consists of a varint followed by a blob of data (the +** key). The varint is the number of bytes in the blob of data. +*/ +static int vdbeSorterListToPMA(sqlite3 *db, VdbeCursor *pCsr){ + int rc = SQLITE_OK; /* Return code */ + VdbeSorter *pSorter = pCsr->pSorter; + + if( pSorter->nInMemory==0 ){ + assert( pSorter->pRecord==0 ); + return rc; + } + + rc = vdbeSorterSort(pCsr); + + /* If the first temporary PMA file has not been opened, open it now. */ + if( rc==SQLITE_OK && pSorter->pTemp1==0 ){ + rc = vdbeSorterOpenTempFile(db, &pSorter->pTemp1); + assert( rc!=SQLITE_OK || pSorter->pTemp1 ); + assert( pSorter->iWriteOff==0 ); + assert( pSorter->nPMA==0 ); + } + + if( rc==SQLITE_OK ){ + i64 iOff = pSorter->iWriteOff; + SorterRecord *p; + SorterRecord *pNext = 0; + static const char eightZeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + pSorter->nPMA++; + rc = vdbeSorterWriteVarint(pSorter->pTemp1, pSorter->nInMemory, &iOff); + for(p=pSorter->pRecord; rc==SQLITE_OK && p; p=pNext){ + pNext = p->pNext; + rc = vdbeSorterWriteVarint(pSorter->pTemp1, p->nVal, &iOff); + + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pSorter->pTemp1, p->pVal, p->nVal, iOff); + iOff += p->nVal; + } + + sqlite3DbFree(db, p); + } + + /* This assert verifies that unless an error has occurred, the size of + ** the PMA on disk is the same as the expected size stored in + ** pSorter->nInMemory. */ + assert( rc!=SQLITE_OK || pSorter->nInMemory==( + iOff-pSorter->iWriteOff-sqlite3VarintLen(pSorter->nInMemory) + )); + + pSorter->iWriteOff = iOff; + if( rc==SQLITE_OK ){ + /* Terminate each file with 8 extra bytes so that from any offset + ** in the file we can always read 9 bytes without a SHORT_READ error */ + rc = sqlite3OsWrite(pSorter->pTemp1, eightZeros, 8, iOff); + } + pSorter->pRecord = p; + } + + return rc; +} + +/* +** Add a record to the sorter. +*/ +int sqlite3VdbeSorterWrite( + sqlite3 *db, /* Database handle */ + VdbeCursor *pCsr, /* Sorter cursor */ + Mem *pVal /* Memory cell containing record */ +){ + VdbeSorter *pSorter = pCsr->pSorter; + int rc = SQLITE_OK; /* Return Code */ + SorterRecord *pNew; /* New list element */ + + assert( pSorter ); + pSorter->nInMemory += sqlite3VarintLen(pVal->n) + pVal->n; + + pNew = (SorterRecord *)sqlite3DbMallocRaw(db, pVal->n + sizeof(SorterRecord)); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + pNew->pVal = (void *)&pNew[1]; + memcpy(pNew->pVal, pVal->z, pVal->n); + pNew->nVal = pVal->n; + pNew->pNext = pSorter->pRecord; + pSorter->pRecord = pNew; + } + + /* See if the contents of the sorter should now be written out. They + ** are written out when either of the following are true: + ** + ** * The total memory allocated for the in-memory list is greater + ** than (page-size * cache-size), or + ** + ** * The total memory allocated for the in-memory list is greater + ** than (page-size * 10) and sqlite3HeapNearlyFull() returns true. + */ + if( rc==SQLITE_OK && pSorter->mxPmaSize>0 && ( + (pSorter->nInMemory>pSorter->mxPmaSize) + || (pSorter->nInMemory>pSorter->mnPmaSize && sqlite3HeapNearlyFull()) + )){ + rc = vdbeSorterListToPMA(db, pCsr); + pSorter->nInMemory = 0; + } + + return rc; +} + +/* +** Helper function for sqlite3VdbeSorterRewind(). +*/ +static int vdbeSorterInitMerge( + sqlite3 *db, /* Database handle */ + VdbeCursor *pCsr, /* Cursor handle for this sorter */ + i64 *pnByte /* Sum of bytes in all opened PMAs */ +){ + VdbeSorter *pSorter = pCsr->pSorter; + int rc = SQLITE_OK; /* Return code */ + int i; /* Used to iterator through aIter[] */ + i64 nByte = 0; /* Total bytes in all opened PMAs */ + + /* Initialize the iterators. */ + for(i=0; iaIter[i]; + rc = vdbeSorterIterInit(db, pSorter, pSorter->iReadOff, pIter, &nByte); + pSorter->iReadOff = pIter->iEof; + assert( rc!=SQLITE_OK || pSorter->iReadOff<=pSorter->iWriteOff ); + if( rc!=SQLITE_OK || pSorter->iReadOff>=pSorter->iWriteOff ) break; + } + + /* Initialize the aTree[] array. */ + for(i=pSorter->nTree-1; rc==SQLITE_OK && i>0; i--){ + rc = vdbeSorterDoCompare(pCsr, i); + } + + *pnByte = nByte; + return rc; +} + +/* +** Once the sorter has been populated, this function is called to prepare +** for iterating through its contents in sorted order. +*/ +int sqlite3VdbeSorterRewind(sqlite3 *db, VdbeCursor *pCsr, int *pbEof){ + VdbeSorter *pSorter = pCsr->pSorter; + int rc; /* Return code */ + sqlite3_file *pTemp2 = 0; /* Second temp file to use */ + i64 iWrite2 = 0; /* Write offset for pTemp2 */ + int nIter; /* Number of iterators used */ + int nByte; /* Bytes of space required for aIter/aTree */ + int N = 2; /* Power of 2 >= nIter */ + + assert( pSorter ); + + /* If no data has been written to disk, then do not do so now. Instead, + ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly + ** from the in-memory list. */ + if( pSorter->nPMA==0 ){ + *pbEof = !pSorter->pRecord; + assert( pSorter->aTree==0 ); + return vdbeSorterSort(pCsr); + } + + /* Write the current b-tree to a PMA. Close the b-tree cursor. */ + rc = vdbeSorterListToPMA(db, pCsr); + if( rc!=SQLITE_OK ) return rc; + + /* Allocate space for aIter[] and aTree[]. */ + nIter = pSorter->nPMA; + if( nIter>SORTER_MAX_MERGE_COUNT ) nIter = SORTER_MAX_MERGE_COUNT; + assert( nIter>0 ); + while( NaIter = (VdbeSorterIter *)sqlite3DbMallocZero(db, nByte); + if( !pSorter->aIter ) return SQLITE_NOMEM; + pSorter->aTree = (int *)&pSorter->aIter[N]; + pSorter->nTree = N; + + do { + int iNew; /* Index of new, merged, PMA */ + + for(iNew=0; + rc==SQLITE_OK && iNew*SORTER_MAX_MERGE_COUNTnPMA; + iNew++ + ){ + i64 nWrite; /* Number of bytes in new PMA */ + + /* If there are SORTER_MAX_MERGE_COUNT or less PMAs in file pTemp1, + ** initialize an iterator for each of them and break out of the loop. + ** These iterators will be incrementally merged as the VDBE layer calls + ** sqlite3VdbeSorterNext(). + ** + ** Otherwise, if pTemp1 contains more than SORTER_MAX_MERGE_COUNT PMAs, + ** initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs + ** are merged into a single PMA that is written to file pTemp2. + */ + rc = vdbeSorterInitMerge(db, pCsr, &nWrite); + assert( rc!=SQLITE_OK || pSorter->aIter[ pSorter->aTree[1] ].pFile ); + if( rc!=SQLITE_OK || pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ + break; + } + + /* Open the second temp file, if it is not already open. */ + if( pTemp2==0 ){ + assert( iWrite2==0 ); + rc = vdbeSorterOpenTempFile(db, &pTemp2); + } + + if( rc==SQLITE_OK ){ + rc = vdbeSorterWriteVarint(pTemp2, nWrite, &iWrite2); + } + + if( rc==SQLITE_OK ){ + int bEof = 0; + while( rc==SQLITE_OK && bEof==0 ){ + int nToWrite; + VdbeSorterIter *pIter = &pSorter->aIter[ pSorter->aTree[1] ]; + assert( pIter->pFile ); + nToWrite = pIter->nKey + sqlite3VarintLen(pIter->nKey); + rc = sqlite3OsWrite(pTemp2, pIter->aAlloc, nToWrite, iWrite2); + iWrite2 += nToWrite; + if( rc==SQLITE_OK ){ + rc = sqlite3VdbeSorterNext(db, pCsr, &bEof); + } + } + } + } + + if( pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ + break; + }else{ + sqlite3_file *pTmp = pSorter->pTemp1; + pSorter->nPMA = iNew; + pSorter->pTemp1 = pTemp2; + pTemp2 = pTmp; + pSorter->iWriteOff = iWrite2; + pSorter->iReadOff = 0; + iWrite2 = 0; + } + }while( rc==SQLITE_OK ); + + if( pTemp2 ){ + sqlite3OsCloseFree(pTemp2); + } + *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + return rc; +} + +/* +** Advance to the next element in the sorter. +*/ +int sqlite3VdbeSorterNext(sqlite3 *db, VdbeCursor *pCsr, int *pbEof){ + VdbeSorter *pSorter = pCsr->pSorter; + int rc; /* Return code */ + + if( pSorter->aTree ){ + int iPrev = pSorter->aTree[1];/* Index of iterator to advance */ + int i; /* Index of aTree[] to recalculate */ + + rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); + for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){ + rc = vdbeSorterDoCompare(pCsr, i); + } + + *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + }else{ + SorterRecord *pFree = pSorter->pRecord; + pSorter->pRecord = pFree->pNext; + pFree->pNext = 0; + vdbeSorterRecordFree(db, pFree); + *pbEof = !pSorter->pRecord; + rc = SQLITE_OK; + } + return rc; +} + +/* +** Return a pointer to a buffer owned by the sorter that contains the +** current key. +*/ +static void *vdbeSorterRowkey( + VdbeSorter *pSorter, /* Sorter object */ + int *pnKey /* OUT: Size of current key in bytes */ +){ + void *pKey; + if( pSorter->aTree ){ + VdbeSorterIter *pIter; + pIter = &pSorter->aIter[ pSorter->aTree[1] ]; + *pnKey = pIter->nKey; + pKey = pIter->aKey; + }else{ + *pnKey = pSorter->pRecord->nVal; + pKey = pSorter->pRecord->pVal; + } + return pKey; +} + +/* +** Copy the current sorter key into the memory cell pOut. +*/ +int sqlite3VdbeSorterRowkey(VdbeCursor *pCsr, Mem *pOut){ + VdbeSorter *pSorter = pCsr->pSorter; + void *pKey; int nKey; /* Sorter key to copy into pOut */ + + pKey = vdbeSorterRowkey(pSorter, &nKey); + if( sqlite3VdbeMemGrow(pOut, nKey, 0) ){ + return SQLITE_NOMEM; + } + pOut->n = nKey; + MemSetTypeFlag(pOut, MEM_Blob); + memcpy(pOut->z, pKey, nKey); + + return SQLITE_OK; +} + +/* +** Compare the key in memory cell pVal with the key that the sorter cursor +** passed as the first argument currently points to. For the purposes of +** the comparison, ignore the rowid field at the end of each record. +** +** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM). +** Otherwise, set *pRes to a negative, zero or positive value if the +** key in pVal is smaller than, equal to or larger than the current sorter +** key. +*/ +int sqlite3VdbeSorterCompare( + VdbeCursor *pCsr, /* Sorter cursor */ + Mem *pVal, /* Value to compare to current sorter key */ + int *pRes /* OUT: Result of comparison */ +){ + VdbeSorter *pSorter = pCsr->pSorter; + void *pKey; int nKey; /* Sorter key to compare pVal with */ + + pKey = vdbeSorterRowkey(pSorter, &nKey); + vdbeSorterCompare(pCsr, 1, pVal->z, pVal->n, pKey, nKey, pRes); + return SQLITE_OK; +} + +#endif /* #ifndef SQLITE_OMIT_MERGE_SORT */ diff --git a/src/vtab.c b/src/vtab.c index 223ef4e7..8119cb55 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -891,7 +891,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ for(i=0; rc==SQLITE_OK && inVTrans; i++){ VTable *pVTab = db->aVTrans[i]; const sqlite3_module *pMod = pVTab->pMod->pModule; - if( pMod->iVersion>=2 ){ + if( pVTab->pVtab && pMod->iVersion>=2 ){ int (*xMethod)(sqlite3_vtab *, int); switch( op ){ case SAVEPOINT_BEGIN: @@ -906,7 +906,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ break; } if( xMethod && pVTab->iSavepoint>iSavepoint ){ - rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint); + rc = xMethod(pVTab->pVtab, iSavepoint); } } } diff --git a/src/wal.c b/src/wal.c index b9a03dff..f2b31871 100644 --- a/src/wal.c +++ b/src/wal.c @@ -1804,13 +1804,15 @@ int sqlite3WalClose( */ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE); if( rc==SQLITE_OK ){ + int bPersistWal = -1; if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } rc = sqlite3WalCheckpoint( pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 ); - if( rc==SQLITE_OK ){ + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal); + if( rc==SQLITE_OK && bPersistWal!=1 ){ isDelete = 1; } } @@ -2341,7 +2343,7 @@ int sqlite3WalRead( int sz; i64 iOffset; sz = pWal->hdr.szPage; - sz = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); + sz = (sz&0xfe00) + ((sz&0x0001)<<16); testcase( sz<=32768 ); testcase( sz>=65536 ); iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE; diff --git a/src/where.c b/src/where.c index cf30d94d..05414da5 100644 --- a/src/where.c +++ b/src/where.c @@ -118,21 +118,31 @@ struct WhereTerm { #define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */ #define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */ #define TERM_OR_OK 0x40 /* Used during OR-clause processing */ -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 # define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ #else -# define TERM_VNULL 0x00 /* Disabled if not using stat2 */ +# define TERM_VNULL 0x00 /* Disabled if not using stat3 */ #endif /* ** An instance of the following structure holds all information about a ** WHERE clause. Mostly this is a container for one or more WhereTerms. +** +** Explanation of pOuter: For a WHERE clause of the form +** +** a AND ((b AND c) OR (d AND e)) AND f +** +** There are separate WhereClause objects for the whole clause and for +** the subclauses "(b AND c)" and "(d AND e)". The pOuter field of the +** subclauses points to the WhereClause object for the whole clause. */ struct WhereClause { Parse *pParse; /* The parser context */ WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */ Bitmask vmask; /* Bitmask identifying virtual table cursors */ + WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ + u16 wctrlFlags; /* Might include WHERE_AND_ONLY */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ @@ -253,6 +263,7 @@ struct WhereCost { #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 */ +#define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */ /* ** Initialize a preallocated WhereClause structure. @@ -260,14 +271,17 @@ struct WhereCost { static void whereClauseInit( WhereClause *pWC, /* The WhereClause to be initialized */ Parse *pParse, /* The parsing context */ - WhereMaskSet *pMaskSet /* Mapping from table cursor numbers to bitmasks */ + WhereMaskSet *pMaskSet, /* Mapping from table cursor numbers to bitmasks */ + u16 wctrlFlags /* Might include WHERE_AND_ONLY */ ){ pWC->pParse = pParse; pWC->pMaskSet = pMaskSet; + pWC->pOuter = 0; pWC->nTerm = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; pWC->vmask = 0; + pWC->wctrlFlags = wctrlFlags; } /* Forward reference */ @@ -466,11 +480,19 @@ static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){ static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){ Bitmask mask = 0; while( pS ){ + SrcList *pSrc = pS->pSrc; mask |= exprListTableUsage(pMaskSet, pS->pEList); mask |= exprListTableUsage(pMaskSet, pS->pGroupBy); mask |= exprListTableUsage(pMaskSet, pS->pOrderBy); mask |= exprTableUsage(pMaskSet, pS->pWhere); mask |= exprTableUsage(pMaskSet, pS->pHaving); + if( ALWAYS(pSrc!=0) ){ + int i; + for(i=0; inSrc; i++){ + mask |= exprSelectTableUsage(pMaskSet, pSrc->a[i].pSelect); + mask |= exprTableUsage(pMaskSet, pSrc->a[i].pOn); + } + } pS = pS->pPrior; } return mask; @@ -575,36 +597,38 @@ static WhereTerm *findTerm( int k; assert( iCur>=0 ); op &= WO_ALL; - for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ - if( pTerm->leftCursor==iCur - && (pTerm->prereqRight & notReady)==0 - && pTerm->u.leftColumn==iColumn - && (pTerm->eOperator & op)!=0 - ){ - if( pIdx && pTerm->eOperator!=WO_ISNULL ){ - Expr *pX = pTerm->pExpr; - CollSeq *pColl; - char idxaff; - int j; - Parse *pParse = pWC->pParse; - - idxaff = pIdx->pTable->aCol[iColumn].affinity; - if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; - - /* Figure out the collation sequence required from an index for - ** it to be useful for optimising expression pX. Store this - ** value in variable pColl. - */ - assert(pX->pLeft); - pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); - assert(pColl || pParse->nErr); - - for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ - if( NEVER(j>=pIdx->nColumn) ) return 0; + for(; pWC; pWC=pWC->pOuter){ + for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ + if( pTerm->leftCursor==iCur + && (pTerm->prereqRight & notReady)==0 + && pTerm->u.leftColumn==iColumn + && (pTerm->eOperator & op)!=0 + ){ + if( pIdx && pTerm->eOperator!=WO_ISNULL ){ + Expr *pX = pTerm->pExpr; + CollSeq *pColl; + char idxaff; + int j; + Parse *pParse = pWC->pParse; + + idxaff = pIdx->pTable->aCol[iColumn].affinity; + if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue; + + /* Figure out the collation sequence required from an index for + ** it to be useful for optimising expression pX. Store this + ** value in variable pColl. + */ + assert(pX->pLeft); + pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); + assert(pColl || pParse->nErr); + + for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ + if( NEVER(j>=pIdx->nColumn) ) return 0; + } + if( pColl && sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; } - if( pColl && sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; + return pTerm; } - return pTerm; } } return 0; @@ -681,7 +705,7 @@ static int isLikeOrGlob( if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = (char *)sqlite3_value_text(pVal); } - sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); /* IMP: R-23257-02778 */ + sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ z = pRight->u.zToken; @@ -699,7 +723,7 @@ static int isLikeOrGlob( *ppPrefix = pPrefix; if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; - sqlite3VdbeSetVarmask(v, pRight->iColumn); /* IMP: R-23257-02778 */ + sqlite3VdbeSetVarmask(v, pRight->iColumn); if( *pisComplete && pRight->u.zToken[1] ){ /* If the rhs of the LIKE expression is a variable, and the current ** value of the variable means there is no need to invoke the LIKE @@ -868,7 +892,7 @@ static void exprAnalyzeOrTerm( if( pOrInfo==0 ) return; pTerm->wtFlags |= TERM_ORINFO; pOrWc = &pOrInfo->wc; - whereClauseInit(pOrWc, pWC->pParse, pMaskSet); + whereClauseInit(pOrWc, pWC->pParse, pMaskSet, pWC->wctrlFlags); whereSplit(pOrWc, pExpr, TK_OR); exprAnalyzeAll(pSrc, pOrWc); if( db->mallocFailed ) return; @@ -895,9 +919,10 @@ static void exprAnalyzeOrTerm( pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; pAndWC = &pAndInfo->wc; - whereClauseInit(pAndWC, pWC->pParse, pMaskSet); + whereClauseInit(pAndWC, pWC->pParse, pMaskSet, pWC->wctrlFlags); whereSplit(pAndWC, pOrTerm->pExpr, TK_AND); exprAnalyzeAll(pSrc, pAndWC); + pAndWC->pOuter = pWC; testcase( db->mallocFailed ); if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ @@ -1331,8 +1356,8 @@ static void exprAnalyze( } #endif /* SQLITE_OMIT_VIRTUALTABLE */ -#ifdef SQLITE_ENABLE_STAT2 - /* When sqlite_stat2 histogram data is available an operator of the +#ifdef SQLITE_ENABLE_STAT3 + /* When sqlite_stat3 histogram data is available an operator of the ** form "x IS NOT NULL" can sometimes be evaluated more efficiently ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a ** virtual term of that form. @@ -1370,7 +1395,7 @@ static void exprAnalyze( pNewTerm->prereqAll = pTerm->prereqAll; } } -#endif /* SQLITE_ENABLE_STAT2 */ +#endif /* SQLITE_ENABLE_STAT */ /* Prevent ON clause terms of a LEFT JOIN from being used to drive ** an index for tables to the left of the join. @@ -1397,6 +1422,162 @@ static int referencesOtherTables( return 0; } +/* +** This function searches the expression list passed as the second argument +** for an expression of type TK_COLUMN that refers to the same column and +** uses the same collation sequence as the iCol'th column of index pIdx. +** Argument iBase is the cursor number used for the table that pIdx refers +** to. +** +** If such an expression is found, its index in pList->a[] is returned. If +** no expression is found, -1 is returned. +*/ +static int findIndexCol( + Parse *pParse, /* Parse context */ + ExprList *pList, /* Expression list to search */ + int iBase, /* Cursor for table associated with pIdx */ + Index *pIdx, /* Index to match column of */ + int iCol /* Column of index to match */ +){ + int i; + const char *zColl = pIdx->azColl[iCol]; + + for(i=0; inExpr; i++){ + Expr *p = pList->a[i].pExpr; + if( p->op==TK_COLUMN + && p->iColumn==pIdx->aiColumn[iCol] + && p->iTable==iBase + ){ + CollSeq *pColl = sqlite3ExprCollSeq(pParse, p); + if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){ + return i; + } + } + } + + return -1; +} + +/* +** This routine determines if pIdx can be used to assist in processing a +** DISTINCT qualifier. In other words, it tests whether or not using this +** index for the outer loop guarantees that rows with equal values for +** all expressions in the pDistinct list are delivered grouped together. +** +** For example, the query +** +** SELECT DISTINCT a, b, c FROM tbl WHERE a = ? +** +** can benefit from any index on columns "b" and "c". +*/ +static int isDistinctIndex( + Parse *pParse, /* Parsing context */ + WhereClause *pWC, /* The WHERE clause */ + Index *pIdx, /* The index being considered */ + int base, /* Cursor number for the table pIdx is on */ + ExprList *pDistinct, /* The DISTINCT expressions */ + int nEqCol /* Number of index columns with == */ +){ + Bitmask mask = 0; /* Mask of unaccounted for pDistinct exprs */ + int i; /* Iterator variable */ + + if( pIdx->zName==0 || pDistinct==0 || pDistinct->nExpr>=BMS ) return 0; + testcase( pDistinct->nExpr==BMS-1 ); + + /* Loop through all the expressions in the distinct list. If any of them + ** are not simple column references, return early. Otherwise, test if the + ** WHERE clause contains a "col=X" clause. If it does, the expression + ** can be ignored. If it does not, and the column does not belong to the + ** same table as index pIdx, return early. Finally, if there is no + ** matching "col=X" expression and the column is on the same table as pIdx, + ** set the corresponding bit in variable mask. + */ + for(i=0; inExpr; i++){ + WhereTerm *pTerm; + Expr *p = pDistinct->a[i].pExpr; + if( p->op!=TK_COLUMN ) return 0; + pTerm = findTerm(pWC, p->iTable, p->iColumn, ~(Bitmask)0, WO_EQ, 0); + if( pTerm ){ + Expr *pX = pTerm->pExpr; + CollSeq *p1 = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); + CollSeq *p2 = sqlite3ExprCollSeq(pParse, p); + if( p1==p2 ) continue; + } + if( p->iTable!=base ) return 0; + mask |= (((Bitmask)1) << i); + } + + for(i=nEqCol; mask && inColumn; i++){ + int iExpr = findIndexCol(pParse, pDistinct, base, pIdx, i); + if( iExpr<0 ) break; + mask &= ~(((Bitmask)1) << iExpr); + } + + return (mask==0); +} + + +/* +** Return true if the DISTINCT expression-list passed as the third argument +** is redundant. A DISTINCT list is redundant if the database contains a +** UNIQUE index that guarantees that the result of the query will be distinct +** anyway. +*/ +static int isDistinctRedundant( + Parse *pParse, + SrcList *pTabList, + WhereClause *pWC, + ExprList *pDistinct +){ + Table *pTab; + Index *pIdx; + int i; + int iBase; + + /* If there is more than one table or sub-select in the FROM clause of + ** this query, then it will not be possible to show that the DISTINCT + ** clause is redundant. */ + if( pTabList->nSrc!=1 ) return 0; + iBase = pTabList->a[0].iCursor; + pTab = pTabList->a[0].pTab; + + /* If any of the expressions is an IPK column on table iBase, then return + ** true. Note: The (p->iTable==iBase) part of this test may be false if the + ** current SELECT is a correlated sub-query. + */ + for(i=0; inExpr; i++){ + Expr *p = pDistinct->a[i].pExpr; + if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1; + } + + /* Loop through all indices on the table, checking each to see if it makes + ** the DISTINCT qualifier redundant. It does so if: + ** + ** 1. The index is itself UNIQUE, and + ** + ** 2. All of the columns in the index are either part of the pDistinct + ** list, or else the WHERE clause contains a term of the form "col=X", + ** where X is a constant value. The collation sequences of the + ** comparison and select-list expressions must match those of the index. + */ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->onError==OE_None ) continue; + for(i=0; inColumn; i++){ + int iCol = pIdx->aiColumn[i]; + if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) + && 0>findIndexCol(pParse, pDistinct, iBase, pIdx, i) + ){ + break; + } + } + if( i==pIdx->nColumn ){ + /* This index implies that the DISTINCT qualifier is redundant. */ + return 1; + } + } + + return 0; +} /* ** This routine decides if pIdx can be used to satisfy the ORDER BY @@ -1433,7 +1614,10 @@ static int isSortingIndex( struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ sqlite3 *db = pParse->db; - assert( pOrderBy!=0 ); + if( !pOrderBy ) return 0; + if( wsFlags & WHERE_COLUMN_IN ) return 0; + if( pIdx->bUnordered ) return 0; + nTerm = pOrderBy->nExpr; assert( nTerm>0 ); @@ -1633,11 +1817,14 @@ 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 INDEXED BY or NOT INDEXED clauses - ** are used */ + /* The OR-clause optimization is disallowed if the INDEXED BY or + ** NOT INDEXED clauses are used or if the WHERE_AND_ONLY bit is set. */ if( pSrc->notIndexed || pSrc->pIndex!=0 ){ return; } + if( pWC->wctrlFlags & WHERE_AND_ONLY ){ + return; + } /* Search the WHERE clause terms for a usable WO_OR term. */ for(pTerm=pWC->a; pTermpParse; tempWC.pMaskSet = pWC->pMaskSet; + tempWC.pOuter = pWC; tempWC.op = TK_AND; tempWC.a = pOrTerm; + tempWC.wctrlFlags = 0; tempWC.nTerm = 1; bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost); }else{ @@ -1746,6 +1935,10 @@ static void bestAutomaticIndex( WhereTerm *pWCEnd; /* End of pWC->a[] */ Table *pTable; /* Table tht might be indexed */ + if( pParse->nQueryLoop<=(double)1 ){ + /* There is no point in building an automatic index for a single scan */ + return; + } if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){ /* Automatic indices are disabled at run-time */ return; @@ -1758,6 +1951,10 @@ static void bestAutomaticIndex( /* The NOT INDEXED clause appears in the SQL. */ return; } + if( pSrc->isCorrelated ){ + /* The source is a correlated sub-query. No point in indexing it. */ + return; + } assert( pParse->nQueryLoop >= (double)1 ); pTable = pSrc->pTab; @@ -1826,8 +2023,7 @@ static void constructAutomaticIndex( v = pParse->pVdbe; assert( v!=0 ); regIsInit = ++pParse->nMem; - addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit); - sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit); + addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit); /* Count the number of columns that will be added to the index ** and used to match WHERE clause constraints */ @@ -1974,6 +2170,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_ISNULL ); if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; + if( pTerm->wtFlags & TERM_VNULL ) continue; nTerm++; } @@ -2024,6 +2221,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_ISNULL ); if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; + if( pTerm->wtFlags & TERM_VNULL ) continue; pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; pIdxCons[j].op = (u8)pTerm->eOperator; @@ -2250,67 +2448,85 @@ static void bestVirtualIndex( } #endif /* SQLITE_OMIT_VIRTUALTABLE */ +#ifdef SQLITE_ENABLE_STAT3 /* -** Argument pIdx is a pointer to an index structure that has an array of -** SQLITE_INDEX_SAMPLES evenly spaced samples of the first indexed column -** stored in Index.aSample. These samples divide the domain of values stored -** the index into (SQLITE_INDEX_SAMPLES+1) regions. -** Region 0 contains all values less than the first sample value. Region -** 1 contains values between the first and second samples. Region 2 contains -** values between samples 2 and 3. And so on. Region SQLITE_INDEX_SAMPLES -** contains values larger than the last sample. +** Estimate the location of a particular key among all keys in an +** index. Store the results in aStat as follows: ** -** If the index contains many duplicates of a single value, then it is -** possible that two or more adjacent samples can hold the same value. -** When that is the case, the smallest possible region code is returned -** when roundUp is false and the largest possible region code is returned -** when roundUp is true. +** aStat[0] Est. number of rows less than pVal +** aStat[1] Est. number of rows equal to pVal ** -** If successful, this function determines which of the regions value -** pVal lies in, sets *piRegion to the region index (a value between 0 -** and SQLITE_INDEX_SAMPLES+1, inclusive) and returns SQLITE_OK. -** Or, if an OOM occurs while converting text values between encodings, -** SQLITE_NOMEM is returned and *piRegion is undefined. +** Return SQLITE_OK on success. */ -#ifdef SQLITE_ENABLE_STAT2 -static int whereRangeRegion( +static int whereKeyStats( Parse *pParse, /* Database connection */ Index *pIdx, /* Index to consider domain of */ sqlite3_value *pVal, /* Value to consider */ - int roundUp, /* Return largest valid region if true */ - int *piRegion /* OUT: Region of domain in which value lies */ + int roundUp, /* Round up if true. Round down if false */ + tRowcnt *aStat /* OUT: stats written here */ ){ - assert( roundUp==0 || roundUp==1 ); - if( ALWAYS(pVal) ){ - IndexSample *aSample = pIdx->aSample; - int i = 0; - int eType = sqlite3_value_type(pVal); + tRowcnt n; + IndexSample *aSample; + int i, eType; + int isEq = 0; + i64 v; + double r, rS; - if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - double r = sqlite3_value_double(pVal); - for(i=0; i=SQLITE_TEXT ) break; - if( roundUp ){ - if( aSample[i].u.r>r ) break; - }else{ - if( aSample[i].u.r>=r ) break; + assert( roundUp==0 || roundUp==1 ); + assert( pIdx->nSample>0 ); + if( pVal==0 ) return SQLITE_ERROR; + n = pIdx->aiRowEst[0]; + aSample = pIdx->aSample; + eType = sqlite3_value_type(pVal); + + if( eType==SQLITE_INTEGER ){ + v = sqlite3_value_int64(pVal); + r = (i64)v; + for(i=0; inSample; i++){ + if( aSample[i].eType==SQLITE_NULL ) continue; + if( aSample[i].eType>=SQLITE_TEXT ) break; + if( aSample[i].eType==SQLITE_INTEGER ){ + if( aSample[i].u.i>=v ){ + isEq = aSample[i].u.i==v; + break; + } + }else{ + assert( aSample[i].eType==SQLITE_FLOAT ); + if( aSample[i].u.r>=r ){ + isEq = aSample[i].u.r==r; + break; } } - }else if( eType==SQLITE_NULL ){ - i = 0; - if( roundUp ){ - while( inSample; i++){ + if( aSample[i].eType==SQLITE_NULL ) continue; + if( aSample[i].eType>=SQLITE_TEXT ) break; + if( aSample[i].eType==SQLITE_FLOAT ){ + rS = aSample[i].u.r; + }else{ + rS = aSample[i].u.i; } - }else{ + if( rS>=r ){ + isEq = rS==r; + break; + } + } + }else if( eType==SQLITE_NULL ){ + i = 0; + if( aSample[0].eType==SQLITE_NULL ) isEq = 1; + }else{ + assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); + for(i=0; inSample; i++){ + if( aSample[i].eType==SQLITE_TEXT || aSample[i].eType==SQLITE_BLOB ){ + break; + } + } + if( inSample ){ sqlite3 *db = pParse->db; CollSeq *pColl; const u8 *z; - int n; - - /* pVal comes from sqlite3ValueFromExpr() so the type cannot be NULL */ - assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); - if( eType==SQLITE_BLOB ){ z = (const u8 *)sqlite3_value_blob(pVal); pColl = db->pDfltColl; @@ -2329,12 +2545,12 @@ static int whereRangeRegion( assert( z && pColl && pColl->xCmp ); } n = sqlite3ValueBytes(pVal, pColl->enc); - - for(i=0; inSample; i++){ int c; int eSampletype = aSample[i].eType; - if( eSampletype==SQLITE_NULL || eSampletypeenc!=SQLITE_UTF8 ){ int nSample; @@ -2352,16 +2568,47 @@ static int whereRangeRegion( { c = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z); } - if( c-roundUp>=0 ) break; + if( c>=0 ){ + if( c==0 ) isEq = 1; + break; + } } } + } - assert( i>=0 && i<=SQLITE_INDEX_SAMPLES ); - *piRegion = i; + /* At this point, aSample[i] is the first sample that is greater than + ** or equal to pVal. Or if i==pIdx->nSample, then all samples are less + ** than pVal. If aSample[i]==pVal, then isEq==1. + */ + if( isEq ){ + assert( inSample ); + aStat[0] = aSample[i].nLt; + aStat[1] = aSample[i].nEq; + }else{ + tRowcnt iLower, iUpper, iGap; + if( i==0 ){ + iLower = 0; + iUpper = aSample[0].nLt; + }else{ + iUpper = i>=pIdx->nSample ? n : aSample[i].nLt; + iLower = aSample[i-1].nEq + aSample[i-1].nLt; + } + aStat[1] = pIdx->avgEq; + if( iLower>=iUpper ){ + iGap = 0; + }else{ + iGap = iUpper - iLower; + } + if( roundUp ){ + iGap = (iGap*2)/3; + }else{ + iGap = iGap/3; + } + aStat[0] = iLower + iGap; } return SQLITE_OK; } -#endif /* #ifdef SQLITE_ENABLE_STAT2 */ +#endif /* SQLITE_ENABLE_STAT3 */ /* ** If expression pExpr represents a literal value, set *pp to point to @@ -2379,7 +2626,7 @@ static int whereRangeRegion( ** ** If an error occurs, return an error code. Otherwise, SQLITE_OK. */ -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 static int valueFromExpr( Parse *pParse, Expr *pExpr, @@ -2390,7 +2637,7 @@ static int valueFromExpr( || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) ){ int iVar = pExpr->iColumn; - sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-23257-02778 */ + sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff); return SQLITE_OK; } @@ -2427,17 +2674,15 @@ static int valueFromExpr( ** ** then nEq should be passed 0. ** -** The returned value is an integer between 1 and 100, inclusive. A return -** value of 1 indicates that the proposed range scan is expected to visit -** approximately 1/100th (1%) of the rows selected by the nEq equality -** constraints (if any). A return value of 100 indicates that it is expected -** that the range scan will visit every row (100%) selected by the equality -** constraints. +** The returned value is an integer divisor to reduce the estimated +** search space. A return value of 1 means that range constraints are +** no help at all. A return value of 2 means range constraints are +** expected to reduce the search space by half. And so forth... ** -** In the absence of sqlite_stat2 ANALYZE data, each range inequality -** reduces the search space by 3/4ths. Hence a single constraint (x>?) -** results in a return of 25 and a range constraint (x>? AND x?) +** results in a return of 4 and a range constraint (x>? AND xaCol[] of the range-compared column */ WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ - int *piEst /* OUT: Return value */ + double *pRangeDiv /* OUT: Reduce search space by this divisor */ ){ int rc = SQLITE_OK; -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 - if( nEq==0 && p->aSample ){ - sqlite3_value *pLowerVal = 0; - sqlite3_value *pUpperVal = 0; - int iEst; - int iLower = 0; - int iUpper = SQLITE_INDEX_SAMPLES; - int roundUpUpper = 0; - int roundUpLower = 0; + if( nEq==0 && p->nSample ){ + sqlite3_value *pRangeVal; + tRowcnt iLower = 0; + tRowcnt iUpper = p->aiRowEst[0]; + tRowcnt a[2]; u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pLower ){ Expr *pExpr = pLower->pExpr->pRight; - rc = valueFromExpr(pParse, pExpr, aff, &pLowerVal); + rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE ); - roundUpLower = (pLower->eOperator==WO_GT) ?1:0; + if( rc==SQLITE_OK + && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK + ){ + iLower = a[0]; + if( pLower->eOperator==WO_GT ) iLower += a[1]; + } + sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK && pUpper ){ Expr *pExpr = pUpper->pExpr->pRight; - rc = valueFromExpr(pParse, pExpr, aff, &pUpperVal); + rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE ); - roundUpUpper = (pUpper->eOperator==WO_LE) ?1:0; - } - - if( rc!=SQLITE_OK || (pLowerVal==0 && pUpperVal==0) ){ - sqlite3ValueFree(pLowerVal); - sqlite3ValueFree(pUpperVal); - goto range_est_fallback; - }else if( pLowerVal==0 ){ - rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper); - if( pLower ) iLower = iUpper/2; - }else if( pUpperVal==0 ){ - rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower); - if( pUpper ) iUpper = (iLower + SQLITE_INDEX_SAMPLES + 1)/2; - }else{ - rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper); - if( rc==SQLITE_OK ){ - rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower); + if( rc==SQLITE_OK + && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK + ){ + iUpper = a[0]; + if( pUpper->eOperator==WO_LE ) iUpper += a[1]; } + sqlite3ValueFree(pRangeVal); } - WHERETRACE(("range scan regions: %d..%d\n", iLower, iUpper)); - - iEst = iUpper - iLower; - testcase( iEst==SQLITE_INDEX_SAMPLES ); - assert( iEst<=SQLITE_INDEX_SAMPLES ); - if( iEst<1 ){ - *piEst = 50/SQLITE_INDEX_SAMPLES; - }else{ - *piEst = (iEst*100)/SQLITE_INDEX_SAMPLES; + if( rc==SQLITE_OK ){ + if( iUpper<=iLower ){ + *pRangeDiv = (double)p->aiRowEst[0]; + }else{ + *pRangeDiv = (double)p->aiRowEst[0]/(double)(iUpper - iLower); + } + WHERETRACE(("range scan regions: %u..%u div=%g\n", + (u32)iLower, (u32)iUpper, *pRangeDiv)); + return SQLITE_OK; } - sqlite3ValueFree(pLowerVal); - sqlite3ValueFree(pUpperVal); - return rc; } -range_est_fallback: #else UNUSED_PARAMETER(pParse); UNUSED_PARAMETER(p); UNUSED_PARAMETER(nEq); #endif assert( pLower || pUpper ); - *piEst = 100; - if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *piEst /= 4; - if( pUpper ) *piEst /= 4; + *pRangeDiv = (double)1; + if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= (double)4; + if( pUpper ) *pRangeDiv *= (double)4; return rc; } -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 /* ** Estimate the number of rows that will be returned based on ** an equality constraint x=VALUE and where that VALUE occurs in ** the histogram data. This only works when x is the left-most -** column of an index and sqlite_stat2 histogram data is available +** column of an index and sqlite_stat3 histogram data is available ** for that index. When pExpr==NULL that means the constraint is ** "x IS NULL" instead of "x=VALUE". ** @@ -2542,12 +2775,12 @@ static int whereEqualScanEst( double *pnRow /* Write the revised row estimate here */ ){ sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */ - int iLower, iUpper; /* Range of histogram regions containing pRhs */ u8 aff; /* Column affinity */ int rc; /* Subfunction return code */ - double nRowEst; /* New estimate of the number of rows */ + tRowcnt a[2]; /* Statistics */ assert( p->aSample!=0 ); + assert( p->nSample>0 ); aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pExpr ){ rc = valueFromExpr(pParse, pExpr, aff, &pRhs); @@ -2556,26 +2789,18 @@ static int whereEqualScanEst( pRhs = sqlite3ValueNew(pParse->db); } if( pRhs==0 ) return SQLITE_NOTFOUND; - rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower); - if( rc ) goto whereEqualScanEst_cancel; - rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper); - if( rc ) goto whereEqualScanEst_cancel; - WHERETRACE(("equality scan regions: %d..%d\n", iLower, iUpper)); - if( iLower>=iUpper ){ - nRowEst = p->aiRowEst[0]/(SQLITE_INDEX_SAMPLES*2); - if( nRowEst<*pnRow ) *pnRow = nRowEst; - }else{ - nRowEst = (iUpper-iLower)*p->aiRowEst[0]/SQLITE_INDEX_SAMPLES; - *pnRow = nRowEst; + rc = whereKeyStats(pParse, p, pRhs, 0, a); + if( rc==SQLITE_OK ){ + WHERETRACE(("equality scan regions: %d\n", (int)a[1])); + *pnRow = a[1]; } - whereEqualScanEst_cancel: sqlite3ValueFree(pRhs); return rc; } -#endif /* defined(SQLITE_ENABLE_STAT2) */ +#endif /* defined(SQLITE_ENABLE_STAT3) */ -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 /* ** Estimate the number of rows that will be returned based on ** an IN constraint where the right-hand side of the IN operator @@ -2598,60 +2823,25 @@ static int whereInScanEst( ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ double *pnRow /* Write the revised row estimate here */ ){ - sqlite3_value *pVal = 0; /* One value from list */ - int iLower, iUpper; /* Range of histogram regions containing pRhs */ - u8 aff; /* Column affinity */ - int rc = SQLITE_OK; /* Subfunction return code */ - double nRowEst; /* New estimate of the number of rows */ - int nSpan = 0; /* Number of histogram regions spanned */ - int nSingle = 0; /* Histogram regions hit by a single value */ - int nNotFound = 0; /* Count of values that are not constants */ - int i; /* Loop counter */ - u8 aSpan[SQLITE_INDEX_SAMPLES+1]; /* Histogram regions that are spanned */ - u8 aSingle[SQLITE_INDEX_SAMPLES+1]; /* Histogram regions hit once */ + int rc = SQLITE_OK; /* Subfunction return code */ + double nEst; /* Number of rows for a single term */ + double nRowEst = (double)0; /* New estimate of the number of rows */ + int i; /* Loop counter */ assert( p->aSample!=0 ); - aff = p->pTable->aCol[p->aiColumn[0]].affinity; - memset(aSpan, 0, sizeof(aSpan)); - memset(aSingle, 0, sizeof(aSingle)); - for(i=0; inExpr; i++){ - sqlite3ValueFree(pVal); - rc = valueFromExpr(pParse, pList->a[i].pExpr, aff, &pVal); - if( rc ) break; - if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){ - nNotFound++; - continue; - } - rc = whereRangeRegion(pParse, p, pVal, 0, &iLower); - if( rc ) break; - rc = whereRangeRegion(pParse, p, pVal, 1, &iUpper); - if( rc ) break; - if( iLower>=iUpper ){ - aSingle[iLower] = 1; - }else{ - assert( iLower>=0 && iUpper<=SQLITE_INDEX_SAMPLES ); - while( iLowernExpr; i++){ + nEst = p->aiRowEst[0]; + rc = whereEqualScanEst(pParse, p, pList->a[i].pExpr, &nEst); + nRowEst += nEst; } if( rc==SQLITE_OK ){ - for(i=nSpan=0; i<=SQLITE_INDEX_SAMPLES; i++){ - if( aSpan[i] ){ - nSpan++; - }else if( aSingle[i] ){ - nSingle++; - } - } - nRowEst = (nSpan*2+nSingle)*p->aiRowEst[0]/(2*SQLITE_INDEX_SAMPLES) - + nNotFound*p->aiRowEst[1]; if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0]; *pnRow = nRowEst; - WHERETRACE(("IN row estimate: nSpan=%d, nSingle=%d, nNotFound=%d, est=%g\n", - nSpan, nSingle, nNotFound, nRowEst)); + WHERETRACE(("IN row estimate: est=%g\n", nRowEst)); } - sqlite3ValueFree(pVal); return rc; } -#endif /* defined(SQLITE_ENABLE_STAT2) */ +#endif /* defined(SQLITE_ENABLE_STAT3) */ /* @@ -2689,6 +2879,7 @@ static void bestBtreeIndex( Bitmask notReady, /* Mask of cursors not available for indexing */ Bitmask notValid, /* Cursors not available for any purpose */ ExprList *pOrderBy, /* The ORDER BY clause */ + ExprList *pDistinct, /* The select-list if query is DISTINCT */ WhereCost *pCost /* Lowest cost query plan */ ){ int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ @@ -2697,7 +2888,7 @@ static void bestBtreeIndex( int eqTermMask; /* Current mask of valid equality operators */ int idxEqTermMask; /* Index mask of valid equality operators */ Index sPk; /* A fake index object for the primary key */ - unsigned int aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ + tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ int wsFlagMask; /* Allowed flags in pCost->plan.wsFlag */ @@ -2752,10 +2943,10 @@ static void bestBtreeIndex( /* Loop over all indices looking for the best one to use */ for(; pProbe; pIdx=pProbe=pProbe->pNext){ - const unsigned int * const aiRowEst = pProbe->aiRowEst; + const tRowcnt * const aiRowEst = pProbe->aiRowEst; double cost; /* Cost of using pProbe */ double nRow; /* Estimated number of rows in result set */ - double log10N; /* base-10 logarithm of nRow (inexact) */ + double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */ int rev; /* True to scan in reverse order */ int wsFlags = 0; Bitmask used = 0; @@ -2795,14 +2986,12 @@ static void bestBtreeIndex( ** IN operator must be a SELECT, not a value list, for this variable ** to be true. ** - ** 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/4rd its original size. So an x>? constraint reduces - ** estBound to 25. Two constraints (x>? AND xpWC!=pWC ); if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; wsFlags |= WHERE_COLUMN_IN; @@ -2856,28 +3047,30 @@ static void bestBtreeIndex( }else if( pTerm->eOperator & WO_ISNULL ){ wsFlags |= WHERE_COLUMN_NULL; } -#ifdef SQLITE_ENABLE_STAT2 +#ifdef SQLITE_ENABLE_STAT3 if( nEq==0 && pProbe->aSample ) pFirstTerm = pTerm; #endif used |= pTerm->prereqRight; } - /* Determine the value of estBound. */ + /* Determine the value of rangeDiv */ if( nEqnColumn && pProbe->bUnordered==0 ){ 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, &estBound); + whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &rangeDiv); if( pTop ){ nBound = 1; wsFlags |= WHERE_TOP_LIMIT; used |= pTop->prereqRight; + testcase( pTop->pWC!=pWC ); } if( pBtm ){ nBound++; wsFlags |= WHERE_BTM_LIMIT; used |= pBtm->prereqRight; + testcase( pBtm->pWC!=pWC ); } wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE); } @@ -2893,17 +3086,20 @@ static void bestBtreeIndex( ** naturally scan rows in the required order, set the appropriate flags ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index ** will scan rows in a different order, set the bSort variable. */ - if( pOrderBy ){ - if( (wsFlags & WHERE_COLUMN_IN)==0 - && pProbe->bUnordered==0 - && isSortingIndex(pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, - nEq, wsFlags, &rev) - ){ - wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; - wsFlags |= (rev ? WHERE_REVERSE : 0); - }else{ - bSort = 1; - } + if( isSortingIndex( + pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev) + ){ + bSort = 0; + wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; + wsFlags |= (rev ? WHERE_REVERSE : 0); + } + + /* If there is a DISTINCT qualifier and this index will scan rows in + ** order of the DISTINCT expressions, clear bDist and set the appropriate + ** flags in wsFlags. */ + if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq) ){ + bDist = 0; + wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT; } /* If currently calculating the cost of using an index (not the IPK @@ -2937,27 +3133,30 @@ static void bestBtreeIndex( nInMul = (int)(nRow / aiRowEst[nEq]); } -#ifdef SQLITE_ENABLE_STAT2 - /* If the constraint is of the form x=VALUE and histogram +#ifdef SQLITE_ENABLE_STAT3 + /* If the constraint is of the form x=VALUE or x IN (E1,E2,...) + ** and we do not think that values of x are unique and if histogram ** data is available for column x, then it might be possible ** to get a better estimate on the number of rows based on ** VALUE and how common that value is according to the histogram. */ - if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 ){ + if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){ + assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 ); if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ testcase( pFirstTerm->eOperator==WO_EQ ); testcase( pFirstTerm->eOperator==WO_ISNULL ); whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow); - }else if( pFirstTerm->eOperator==WO_IN && bInEst==0 ){ + }else if( bInEst==0 ){ + assert( pFirstTerm->eOperator==WO_IN ); whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow); } } -#endif /* SQLITE_ENABLE_STAT2 */ +#endif /* SQLITE_ENABLE_STAT3 */ /* Adjust the number of output rows and downward to reflect rows ** that are excluded by range constraints. */ - nRow = (nRow * (double)estBound) / (double)100; + nRow = nRow/rangeDiv; if( nRow<1 ) nRow = 1; /* Experiments run on real SQLite databases show that the time needed @@ -2968,7 +3167,7 @@ static void bestBtreeIndex( ** slower with larger records, presumably because fewer records fit ** on one page and hence more pages have to be fetched. ** - ** The ANALYZE command and the sqlite_stat1 and sqlite_stat2 tables do + ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do ** not give us data on the relative sizes of table and index records. ** So this computation assumes table records are about twice as big ** as index records @@ -3020,6 +3219,9 @@ static void bestBtreeIndex( if( bSort ){ cost += nRow*estLog(nRow)*3; } + if( bDist ){ + cost += nRow*estLog(nRow)*3; + } /**** Cost of using this index has now been computed ****/ @@ -3083,10 +3285,10 @@ static void bestBtreeIndex( WHERETRACE(( - "%s(%s): nEq=%d nInMul=%d estBound=%d bSort=%d bLookup=%d wsFlags=0x%x\n" + "%s(%s): nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%x\n" " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n", pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"), - nEq, nInMul, estBound, bSort, bLookup, wsFlags, + nEq, nInMul, (int)rangeDiv, bSort, bLookup, wsFlags, notReady, log10N, nRow, cost, used )); @@ -3165,7 +3367,7 @@ static void bestIndex( }else #endif { - bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); + bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, 0, pCost); } } @@ -3590,7 +3792,8 @@ static Bitmask codeOneLoopStart( WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ - Bitmask notReady /* Which tables are currently available */ + Bitmask notReady, /* Which tables are currently available */ + Expr *pWhere /* Complete WHERE clause */ ){ int j, k; /* Loop counters */ int iCur; /* The VDBE cursor for the table */ @@ -4072,7 +4275,8 @@ static Bitmask codeOneLoopStart( int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ - int ii; + int ii; /* Loop counter */ + Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ pTerm = pLevel->plan.u.pTerm; assert( pTerm!=0 ); @@ -4122,13 +4326,28 @@ static Bitmask codeOneLoopStart( } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); + /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y + ** Then for every term xN, evaluate as the subexpression: xN AND z + ** That way, terms in y that are factored into the disjunction will + ** be picked up by the recursive calls to sqlite3WhereBegin() below. + */ + if( pWC->nTerm>1 ){ + pAndExpr = sqlite3ExprAlloc(pParse->db, TK_AND, 0, 0); + pAndExpr->pRight = pWhere; + } + for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ + Expr *pOrExpr = pOrTerm->pExpr; + if( pAndExpr ){ + pAndExpr->pLeft = pOrExpr; + pOrExpr = pAndExpr; + } /* Loop through table entries that match term pOrTerm. */ - pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0, - WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | + pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, + WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); if( pSubWInfo ){ explainOneScan( @@ -4156,6 +4375,7 @@ static Bitmask codeOneLoopStart( } } } + sqlite3DbFree(pParse->db, pAndExpr); sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); @@ -4368,6 +4588,7 @@ WhereInfo *sqlite3WhereBegin( SrcList *pTabList, /* A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ + ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */ u16 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */ ){ int i; /* Loop counter */ @@ -4428,11 +4649,15 @@ WhereInfo *sqlite3WhereBegin( pWInfo->savedNQueryLoop = pParse->nQueryLoop; pMaskSet = (WhereMaskSet*)&pWC[1]; + /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via + ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ + if( db->flags & SQLITE_DistinctOpt ) pDistinct = 0; + /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. */ initMaskSet(pMaskSet); - whereClauseInit(pWC, pParse, pMaskSet); + whereClauseInit(pWC, pParse, pMaskSet, wctrlFlags); sqlite3ExprCodeConstants(pParse, pWhere); whereSplit(pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ @@ -4495,6 +4720,15 @@ WhereInfo *sqlite3WhereBegin( goto whereBeginError; } + /* Check if the DISTINCT qualifier, if there is one, is redundant. + ** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to + ** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT. + */ + if( pDistinct && isDistinctRedundant(pParse, pTabList, pWC, pDistinct) ){ + pDistinct = 0; + pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + } + /* Chose the best index to use for each table in the FROM clause. ** ** This loop fills in the following fields: @@ -4578,6 +4812,7 @@ WhereInfo *sqlite3WhereBegin( int doNotReorder; /* True if this table should not be reordered */ WhereCost sCost; /* Cost information from best[Virtual]Index() */ ExprList *pOrderBy; /* ORDER BY clause for index to optimize */ + ExprList *pDist; /* DISTINCT clause for index to optimize */ doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0; if( j!=iFrom && doNotReorder ) break; @@ -4588,6 +4823,7 @@ WhereInfo *sqlite3WhereBegin( } mask = (isOptimal ? m : notReady); pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0); + pDist = (i==0 ? pDistinct : 0); if( pTabItem->pIndex==0 ) nUnconstrained++; WHERETRACE(("=== trying table %d with isOptimal=%d ===\n", @@ -4602,7 +4838,7 @@ WhereInfo *sqlite3WhereBegin( #endif { bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, - &sCost); + pDist, &sCost); } assert( isOptimal || (sCost.used¬Ready)==0 ); @@ -4660,9 +4896,14 @@ WhereInfo *sqlite3WhereBegin( WHERETRACE(("*** Optimizer selects table %d for loop %d" " with cost=%g and nRow=%g\n", bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow)); - if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){ + /* The ALWAYS() that follows was added to hush up clang scan-build */ + if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 && ALWAYS(ppOrderBy) ){ *ppOrderBy = 0; } + if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){ + assert( pWInfo->eDistinct==0 ); + pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; + } andFlags &= bestPlan.plan.wsFlags; pLevel->plan = bestPlan.plan; testcase( bestPlan.plan.wsFlags & WHERE_INDEXED ); @@ -4745,7 +4986,7 @@ WhereInfo *sqlite3WhereBegin( }else #endif if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 - && (wctrlFlags & WHERE_OMIT_OPEN)==0 ){ + && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); testcase( pTab->nCol==BMS-1 ); @@ -4790,7 +5031,7 @@ WhereInfo *sqlite3WhereBegin( for(i=0; ia[i]; explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags); - notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady); + notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady, pWhere); pWInfo->iContinue = pLevel->addrCont; } @@ -4925,7 +5166,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ assert( pTab!=0 ); if( (pTab->tabFlags & TF_Ephemeral)==0 && pTab->pSelect==0 - && (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 + && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ int ws = pLevel->plan.wsFlags; if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){ diff --git a/test/8_3_names.test b/test/8_3_names.test index 418685e6..b53e28a9 100644 --- a/test/8_3_names.test +++ b/test/8_3_names.test @@ -67,8 +67,8 @@ do_test 8_3_names-2.1 { file exists test.nal } 1 forcedelete test2.db test2.nal test2.db-journal -file copy test.db test2.db -file copy test.nal test2.nal +copy_file test.db test2.db +copy_file test.nal test2.nal do_test 8_3_names-2.2 { db eval { COMMIT; @@ -101,8 +101,8 @@ do_test 8_3_names-3.1 { file exists test.nal } 0 forcedelete test2.db test2.nal test2.db-journal -file copy test.db test2.db -file copy test.db-journal test2.db-journal +copy_file test.db test2.db +copy_file test.db-journal test2.db-journal do_test 8_3_names-3.2 { db eval { COMMIT; diff --git a/test/all.test b/test/all.test index 96712466..54302d02 100644 --- a/test/all.test +++ b/test/all.test @@ -38,6 +38,7 @@ run_test_suite pcache10 run_test_suite pcache50 run_test_suite pcache90 run_test_suite pcache100 +run_test_suite prepare if {$::tcl_platform(platform)=="unix"} { ifcapable !default_autovacuum { diff --git a/test/alter.test b/test/alter.test index 359034d5..1481bc20 100644 --- a/test/alter.test +++ b/test/alter.test @@ -221,8 +221,8 @@ do_test alter-1.7 { # ifcapable attach { do_test alter-1.8.1 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { ATTACH 'test2.db' AS aux; } @@ -412,8 +412,8 @@ do_test alter-3.1.8 { # Make sure "ON" cannot be used as a database, table or column name without # quoting. Otherwise the sqlite_alter_trigger() function might not work. -file delete -force test3.db -file delete -force test3.db-journal +forcedelete test3.db +forcedelete test3.db-journal ifcapable attach { do_test alter-3.2.1 { catchsql { @@ -846,7 +846,7 @@ do_test alter-14.2 { set system_table_list {1 sqlite_master} catchsql ANALYZE ifcapable analyze { lappend system_table_list 2 sqlite_stat1 } -ifcapable stat2 { lappend system_table_list 3 sqlite_stat2 } +ifcapable stat3 { lappend system_table_list 4 sqlite_stat3 } foreach {tn tbl} $system_table_list { do_test alter-15.$tn.1 { diff --git a/test/alter2.test b/test/alter2.test index 712960c0..14be637f 100644 --- a/test/alter2.test +++ b/test/alter2.test @@ -137,6 +137,7 @@ do_test alter2-1.8 { do_test alter2-1.9 { # ALTER TABLE abc ADD COLUMN d; alter_table abc {CREATE TABLE abc(a, b, c, d);} + if {[permutation] == "prepare"} { db cache flush } execsql { SELECT * FROM abc; } execsql { UPDATE abc SET d = 11 WHERE c IS NULL AND a<4; @@ -314,8 +315,8 @@ do_test alter2-6.1 { } {2} ifcapable attach { do_test alter2-6.2 { - file delete -force test2.db-journal - file delete -force test2.db + forcedelete test2.db-journal + forcedelete test2.db execsql { ATTACH 'test2.db' AS aux; CREATE TABLE aux.t1(a, b); diff --git a/test/alter3.test b/test/alter3.test index 74ba33c5..28d293e2 100644 --- a/test/alter3.test +++ b/test/alter3.test @@ -196,7 +196,7 @@ ifcapable schema_version { do_test alter3-4.1 { db close - file delete -force test.db + forcedelete test.db set ::DB [sqlite3 db test.db] execsql { PRAGMA legacy_file_format=ON; @@ -237,8 +237,8 @@ do_test alter3-4.99 { ifcapable attach { do_test alter3-5.1 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 'one'); diff --git a/test/alter4.test b/test/alter4.test index 738db3fd..cda45533 100644 --- a/test/alter4.test +++ b/test/alter4.test @@ -178,7 +178,7 @@ ifcapable schema_version { do_test alter4-4.1 { db close - file delete -force test.db + forcedelete test.db set ::DB [sqlite3 db test.db] execsql { CREATE TEMP TABLE t1(a, b); @@ -213,8 +213,8 @@ do_test alter4-4.99 { ifcapable attach { do_test alter4-5.1 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { CREATE TEMP TABLE t1(a, b); INSERT INTO t1 VALUES(1, 'one'); diff --git a/test/analyze.test b/test/analyze.test index 766cd50d..362702a9 100644 --- a/test/analyze.test +++ b/test/analyze.test @@ -287,6 +287,64 @@ do_test analyze-4.3 { } } {} +# Verify that DROP TABLE and DROP INDEX remove entries from the +# sqlite_stat1 and sqlite_stat3 tables. +# +do_test analyze-5.0 { + execsql { + DELETE FROM t3; + DELETE FROM t4; + INSERT INTO t3 VALUES(1,2,3,4); + INSERT INTO t3 VALUES(5,6,7,8); + INSERT INTO t3 SELECT a+8, b+8, c+8, d+8 FROM t3; + INSERT INTO t3 SELECT a+16, b+16, c+16, d+16 FROM t3; + INSERT INTO t3 SELECT a+32, b+32, c+32, d+32 FROM t3; + INSERT INTO t3 SELECT a+64, b+64, c+64, d+64 FROM t3; + INSERT INTO t4 SELECT a, b, c FROM t3; + ANALYZE; + SELECT DISTINCT idx FROM sqlite_stat1 ORDER BY 1; + SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; + } +} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4} +ifcapable stat3 { + do_test analyze-5.1 { + execsql { + SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1; + SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1; + } + } {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4} +} +do_test analyze-5.2 { + execsql { + DROP INDEX t3i2; + SELECT DISTINCT idx FROM sqlite_stat1 ORDER BY 1; + SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; + } +} {t3i1 t3i3 t4i1 t4i2 t3 t4} +ifcapable stat3 { + do_test analyze-5.3 { + execsql { + SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1; + SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1; + } + } {t3i1 t3i3 t4i1 t4i2 t3 t4} +} +do_test analyze-5.4 { + execsql { + DROP TABLE t3; + SELECT DISTINCT idx FROM sqlite_stat1 ORDER BY 1; + SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; + } +} {t4i1 t4i2 t4} +ifcapable stat3 { + do_test analyze-5.5 { + execsql { + SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1; + SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1; + } + } {t4i1 t4i2 t4} +} + # This test corrupts the database file so it must be the last test # in the series. # diff --git a/test/analyze2.test b/test/analyze2.test deleted file mode 100644 index de2567bb..00000000 --- a/test/analyze2.test +++ /dev/null @@ -1,554 +0,0 @@ -# 2009 August 06 -# -# 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. This file -# implements tests for the extra functionality provided by the ANALYZE -# command when the library is compiled with SQLITE_ENABLE_STAT2 defined. -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl - -ifcapable !stat2 { - finish_test - return -} - -set testprefix analyze2 - -# 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: -# -# analyze2-1.*: Tests to verify that ANALYZE creates and populates the -# sqlite_stat2 table as expected. -# -# analyze2-2.*: Test that when a table has two indexes on it and either -# index may be used for the scan, the index suggested by -# the contents of sqlite_stat2 table is prefered. -# -# analyze2-3.*: Similar to the previous block of tests, but using tables -# that contain a mixture of NULL, numeric, text and blob -# values. -# -# analyze2-4.*: Check that when an indexed column uses a collation other -# than BINARY, the collation is taken into account when -# using the contents of sqlite_stat2 to estimate the cost -# of a range scan. -# -# analyze2-5.*: Check that collation sequences are used as described above -# even when the only available version of the collation -# function require UTF-16 encoded arguments. -# -# analyze2-6.*: Check that the library behaves correctly when one of the -# sqlite_stat2 or sqlite_stat1 tables are missing. -# -# analyze2-7.*: Check that in a shared-schema situation, nothing goes -# wrong if sqlite_stat2 data is read by one connection, -# and freed by another. -# - -proc eqp {sql {db db}} { - uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db -} - -do_test analyze2-1.1 { - execsql { CREATE TABLE t1(x PRIMARY KEY) } - for {set i 0} {$i < 1000} {incr i} { - execsql { INSERT INTO t1 VALUES($i) } - } - execsql { - ANALYZE; - SELECT * FROM sqlite_stat2; - } -} [list t1 sqlite_autoindex_t1_1 0 50 \ - t1 sqlite_autoindex_t1_1 1 149 \ - t1 sqlite_autoindex_t1_1 2 249 \ - t1 sqlite_autoindex_t1_1 3 349 \ - t1 sqlite_autoindex_t1_1 4 449 \ - t1 sqlite_autoindex_t1_1 5 549 \ - t1 sqlite_autoindex_t1_1 6 649 \ - t1 sqlite_autoindex_t1_1 7 749 \ - t1 sqlite_autoindex_t1_1 8 849 \ - t1 sqlite_autoindex_t1_1 9 949 \ -] - -do_test analyze2-1.2 { - execsql { - DELETE FROM t1 WHERe x>9; - ANALYZE; - SELECT tbl, idx, group_concat(sample, ' ') FROM sqlite_stat2; - } -} {t1 sqlite_autoindex_t1_1 {0 1 2 3 4 5 6 7 8 9}} -do_test analyze2-1.3 { - execsql { - DELETE FROM t1 WHERE x>8; - ANALYZE; - SELECT * FROM sqlite_stat2; - } -} {} -do_test analyze2-1.4 { - execsql { - DELETE FROM t1; - ANALYZE; - SELECT * FROM sqlite_stat2; - } -} {} - -do_test analyze2-2.1 { - execsql { - BEGIN; - DROP TABLE t1; - CREATE TABLE t1(x, y); - CREATE INDEX t1_x ON t1(x); - CREATE INDEX t1_y ON t1(y); - } - for {set i 0} {$i < 1000} {incr i} { - execsql { INSERT INTO t1 VALUES($i, $i) } - } - execsql COMMIT - execsql ANALYZE -} {} -do_eqp_test 2.2 { - SELECT * FROM t1 WHERE x>500 AND y>700 -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)} -} -do_eqp_test 2.3 { - SELECT * FROM t1 WHERE x>700 AND y>500 -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)} -} -do_eqp_test 2.3 { - SELECT * FROM t1 WHERE y>700 AND x>500 -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)} -} -do_eqp_test 2.4 { - SELECT * FROM t1 WHERE y>500 AND x>700 -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)} -} -do_eqp_test 2.5 { - SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700 -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x? AND y? AND x? AND y? AND x? AND y? AND y? AND x'h' -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)} -} -do_eqp_test 3.6 { - SELECT * FROM t1 WHERE x<444 AND y>'h' -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)} -} -do_eqp_test 3.7 { - SELECT * FROM t1 WHERE x<221 AND y>'g' -} { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x 'A' AND a < 'C' AND b > 'A' AND b < 'C' -} { - 0 0 0 {SEARCH TABLE t3 USING INDEX t3b (b>? AND b 'A' AND a < 'c' AND b > 'A' AND b < 'c' -} { - 0 0 0 {SEARCH TABLE t3 USING INDEX t3a (a>? AND a'ccc' - } {0 0 0 {SEARCH TABLE t4 USING COVERING INDEX t4x (x>?) (~800 rows)}} - do_eqp_test 5.4 { - SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg' - } { - 0 0 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~300 rows)} - 0 1 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~800 rows)} - } - do_eqp_test 5.5 { - SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc' - } { - 0 0 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~700 rows)} - 0 1 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~800 rows)} - } -} - -#-------------------------------------------------------------------- -# These tests, analyze2-6.*, verify that the library behaves correctly -# when one of the sqlite_stat1 and sqlite_stat2 tables is missing. -# -# If the sqlite_stat1 table is not present, then the sqlite_stat2 -# table is not read. However, if it is the sqlite_stat2 table that -# is missing, the data in the sqlite_stat1 table is still used. -# -# Tests analyze2-6.1.* test the libary when the sqlite_stat2 table -# is missing. Tests analyze2-6.2.* test the library when sqlite_stat1 -# is not present. -# -do_test analyze2-6.0 { - execsql { - DROP TABLE IF EXISTS t4; - CREATE TABLE t5(a, b); CREATE INDEX t5i ON t5(a, b); - CREATE TABLE t6(a, b); CREATE INDEX t6i ON t6(a, b); - } - for {set ii 0} {$ii < 20} {incr ii} { - execsql { - INSERT INTO t5 VALUES($ii, $ii); - INSERT INTO t6 VALUES($ii/10, $ii/10); - } - } - execsql { - CREATE TABLE master AS - SELECT * FROM sqlite_master WHERE name LIKE 'sqlite_stat%' - } -} {} - -do_test analyze2-6.1.1 { - eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a = 1 AND - t6.a = 1 AND t6.b = 1 - } -} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} -do_test analyze2-6.1.2 { - db cache flush - execsql ANALYZE - eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a = 1 AND - t6.a = 1 AND t6.b = 1 - } -} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} -do_test analyze2-6.1.3 { - sqlite3 db test.db - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a = 1 AND - t6.a = 1 AND t6.b = 1 - } -} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} -do_test analyze2-6.1.4 { - execsql { - PRAGMA writable_schema = 1; - DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat2'; - } - sqlite3 db test.db - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a = 1 AND - t6.a = 1 AND t6.b = 1 - } -} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} -do_test analyze2-6.1.5 { - execsql { - PRAGMA writable_schema = 1; - DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1'; - } - sqlite3 db test.db - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a = 1 AND - t6.a = 1 AND t6.b = 1 - } -} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} -do_test analyze2-6.1.6 { - execsql { - PRAGMA writable_schema = 1; - INSERT INTO sqlite_master SELECT * FROM master; - } - sqlite3 db test.db - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a = 1 AND - t6.a = 1 AND t6.b = 1 - } -} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} - -do_test analyze2-6.2.1 { - execsql { - DELETE FROM sqlite_stat1; - DELETE FROM sqlite_stat2; - } - sqlite3 db test.db - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } -} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a1 AND t5.a<15 AND - t6.a>1 - } -} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} -do_test analyze2-6.2.3 { - sqlite3 db test.db - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } -} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} -do_test analyze2-6.2.4 { - execsql { - PRAGMA writable_schema = 1; - DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1'; - } - sqlite3 db test.db - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } -} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a1 AND t5.a<15 AND - t6.a>1 - } -} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a1 AND t5.a<15 AND - t6.a>1 - } -} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} - -#-------------------------------------------------------------------- -# These tests, analyze2-7.*, test that the sqlite_stat2 functionality -# works in shared-cache mode. Note that these tests reuse the database -# created for the analyze2-6.* tests. -# -ifcapable shared_cache { - db close - set ::enable_shared_cache [sqlite3_enable_shared_cache 1] - - proc incr_schema_cookie {zDb} { - foreach iOffset {24 40} { - set cookie [hexio_get_int [hexio_read $zDb $iOffset 4]] - incr cookie - hexio_write $zDb $iOffset [hexio_render_int32 $cookie] - } - } - - do_test analyze2-7.1 { - sqlite3 db1 test.db - sqlite3 db2 test.db - db1 cache size 0 - db2 cache size 0 - execsql { SELECT count(*) FROM t5 } db1 - } {20} - do_test analyze2-7.2 { - incr_schema_cookie test.db - execsql { SELECT count(*) FROM t5 } db2 - } {20} - do_test analyze2-7.3 { - incr_schema_cookie test.db - execsql { SELECT count(*) FROM t5 } db1 - } {20} - do_test analyze2-7.4 { - incr_schema_cookie test.db - execsql { SELECT count(*) FROM t5 } db2 - } {20} - - do_test analyze2-7.5 { - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } db1 - } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} - do_test analyze2-7.6 { - incr_schema_cookie test.db - execsql { SELECT * FROM sqlite_master } db2 - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } db2 - } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} - do_test analyze2-7.7 { - incr_schema_cookie test.db - execsql { SELECT * FROM sqlite_master } db1 - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } db1 - } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} - - do_test analyze2-7.8 { - execsql { DELETE FROM sqlite_stat2 } db2 - execsql { SELECT * FROM sqlite_master } db1 - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } db1 - } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} - do_test analyze2-7.9 { - execsql { SELECT * FROM sqlite_master } db2 - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } db2 - } {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}} - - do_test analyze2-7.10 { - incr_schema_cookie test.db - execsql { SELECT * FROM sqlite_master } db1 - eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND - t5.a>1 AND t5.a<15 AND - t6.a>1 - } db1 - } {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a200 AND x<300 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x? AND x0 AND x<1100 -} {0 0 0 {SCAN TABLE t1 (~111 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x200 AND x<300 } @@ -117,17 +117,17 @@ do_test analyze3-1.1.6 { } {199 0 14850} do_test analyze3-1.1.7 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } -} {999 999 499500} +} {2000 0 499500} do_test analyze3-1.1.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } -} {999 999 499500} +} {2000 0 499500} do_test analyze3-1.1.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } -} {999 999 499500} +} {2000 0 499500} # The following tests are similar to the block above. The difference is @@ -146,10 +146,10 @@ do_test analyze3-1.2.1 { } {} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 -} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x? AND x0 AND x<99 -} {0 0 0 {SCAN TABLE t2 (~111 rows)}} +} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x12 AND x<20 } } {161 0 4760} @@ -165,17 +165,17 @@ do_test analyze3-1.2.6 { } {161 0 integer integer 4760} do_test analyze3-1.2.7 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } -} {999 999 490555} +} {1981 0 490555} do_test analyze3-1.2.8 { set l [string range "0" 0 end] set u [string range "99" 0 end] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} -} {999 999 text text 490555} +} {1981 0 text text 490555} do_test analyze3-1.2.9 { set l [expr int(0)] set u [expr int(99)] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} -} {999 999 integer integer 490555} +} {1981 0 integer integer 490555} # Same tests a third time. This time, column x has INTEGER affinity and # is not the leftmost column of the table. This triggered a bug causing @@ -193,10 +193,10 @@ do_test analyze3-1.3.1 { } {} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 -} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x? AND x0 AND x<1100 -} {0 0 0 {SCAN TABLE t3 (~111 rows)}} +} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x200 AND x<300 } @@ -213,17 +213,17 @@ do_test analyze3-1.3.6 { } {199 0 14850} do_test analyze3-1.3.7 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } -} {999 999 499500} +} {2000 0 499500} do_test analyze3-1.3.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } -} {999 999 499500} +} {2000 0 499500} do_test analyze3-1.3.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } -} {999 999 499500} +} {2000 0 499500} #------------------------------------------------------------------------- # Test that the values of bound SQL variables may be used for the LIKE @@ -248,7 +248,7 @@ do_test analyze3-2.1 { } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b? AND b=0 AND z<=0} t1z 400 2 {z>=1 AND z<=1} t1z 300 - 3 {z>=2 AND z<=2} t1z 200 - 4 {z>=3 AND z<=3} t1z 100 - 5 {z>=4 AND z<=4} t1z 50 - 6 {z>=-1 AND z<=-1} t1z 50 - 7 {z>1 AND z<3} t1z 200 + 3 {z>=2 AND z<=2} t1z 175 + 4 {z>=3 AND z<=3} t1z 125 + 5 {z>=4 AND z<=4} t1z 1 + 6 {z>=-1 AND z<=-1} t1z 1 + 7 {z>1 AND z<3} t1z 175 8 {z>0 AND z<100} t1z 600 9 {z>=1 AND z<100} t1z 600 10 {z>1 AND z<100} t1z 300 11 {z>=2 AND z<100} t1z 300 - 12 {z>2 AND z<100} t1z 100 - 13 {z>=3 AND z<100} t1z 100 - 14 {z>3 AND z<100} t1z 50 - 15 {z>=4 AND z<100} t1z 50 - 16 {z>=-100 AND z<=-1} t1z 50 + 12 {z>2 AND z<100} t1z 125 + 13 {z>=3 AND z<100} t1z 125 + 14 {z>3 AND z<100} t1z 1 + 15 {z>=4 AND z<100} t1z 1 + 16 {z>=-100 AND z<=-1} t1z 1 17 {z>=-100 AND z<=0} t1z 400 - 18 {z>=-100 AND z<0} t1z 50 + 18 {z>=-100 AND z<0} t1z 1 19 {z>=-100 AND z<=1} t1z 700 20 {z>=-100 AND z<2} t1z 700 - 21 {z>=-100 AND z<=2} t1z 900 - 22 {z>=-100 AND z<3} t1z 900 + 21 {z>=-100 AND z<=2} t1z 875 + 22 {z>=-100 AND z<3} t1z 875 31 {z>=0.0 AND z<=0.0} t1z 400 32 {z>=1.0 AND z<=1.0} t1z 300 - 33 {z>=2.0 AND z<=2.0} t1z 200 - 34 {z>=3.0 AND z<=3.0} t1z 100 - 35 {z>=4.0 AND z<=4.0} t1z 50 - 36 {z>=-1.0 AND z<=-1.0} t1z 50 - 37 {z>1.5 AND z<3.0} t1z 200 - 38 {z>0.5 AND z<100} t1z 600 + 33 {z>=2.0 AND z<=2.0} t1z 175 + 34 {z>=3.0 AND z<=3.0} t1z 125 + 35 {z>=4.0 AND z<=4.0} t1z 1 + 36 {z>=-1.0 AND z<=-1.0} t1z 1 + 37 {z>1.5 AND z<3.0} t1z 174 + 38 {z>0.5 AND z<100} t1z 599 39 {z>=1.0 AND z<100} t1z 600 - 40 {z>1.5 AND z<100} t1z 300 + 40 {z>1.5 AND z<100} t1z 299 41 {z>=2.0 AND z<100} t1z 300 - 42 {z>2.1 AND z<100} t1z 100 - 43 {z>=3.0 AND z<100} t1z 100 - 44 {z>3.2 AND z<100} t1z 50 - 45 {z>=4.0 AND z<100} t1z 50 - 46 {z>=-100 AND z<=-1.0} t1z 50 + 42 {z>2.1 AND z<100} t1z 124 + 43 {z>=3.0 AND z<100} t1z 125 + 44 {z>3.2 AND z<100} t1z 1 + 45 {z>=4.0 AND z<100} t1z 1 + 46 {z>=-100 AND z<=-1.0} t1z 1 47 {z>=-100 AND z<=0.0} t1z 400 - 48 {z>=-100 AND z<0.0} t1z 50 + 48 {z>=-100 AND z<0.0} t1z 1 49 {z>=-100 AND z<=1.0} t1z 700 50 {z>=-100 AND z<2.0} t1z 700 - 51 {z>=-100 AND z<=2.0} t1z 900 - 52 {z>=-100 AND z<3.0} t1z 900 + 51 {z>=-100 AND z<=2.0} t1z 875 + 52 {z>=-100 AND z<3.0} t1z 875 - 101 {z=-1} t1z 50 + 101 {z=-1} t1z 1 102 {z=0} t1z 400 103 {z=1} t1z 300 - 104 {z=2} t1z 200 - 105 {z=3} t1z 100 - 106 {z=4} t1z 50 - 107 {z=-10.0} t1z 50 + 104 {z=2} t1z 175 + 105 {z=3} t1z 125 + 106 {z=4} t1z 1 + 107 {z=-10.0} t1z 1 108 {z=0.0} t1z 400 109 {z=1.0} t1z 300 - 110 {z=2.0} t1z 200 - 111 {z=3.0} t1z 100 - 112 {z=4.0} t1z 50 - 113 {z=1.5} t1z 50 - 114 {z=2.5} t1z 50 + 110 {z=2.0} t1z 175 + 111 {z=3.0} t1z 125 + 112 {z=4.0} t1z 1 + 113 {z=1.5} t1z 1 + 114 {z=2.5} t1z 1 - 201 {z IN (-1)} t1z 50 + 201 {z IN (-1)} t1z 1 202 {z IN (0)} t1z 400 203 {z IN (1)} t1z 300 - 204 {z IN (2)} t1z 200 - 205 {z IN (3)} t1z 100 - 206 {z IN (4)} t1z 50 - 207 {z IN (0.5)} t1z 50 + 204 {z IN (2)} t1z 175 + 205 {z IN (3)} t1z 125 + 206 {z IN (4)} t1z 1 + 207 {z IN (0.5)} t1z 1 208 {z IN (0,1)} t1z 700 - 209 {z IN (0,1,2)} t1z 900 + 209 {z IN (0,1,2)} t1z 875 210 {z IN (0,1,2,3)} {} 100 211 {z IN (0,1,2,3,4,5)} {} 100 - 212 {z IN (1,2)} t1z 500 + 212 {z IN (1,2)} t1z 475 213 {z IN (2,3)} t1z 300 214 {z=3 OR z=2} t1z 300 - 215 {z IN (-1,3)} t1z 150 - 216 {z=-1 OR z=3} t1z 150 + 215 {z IN (-1,3)} t1z 126 + 216 {z=-1 OR z=3} t1z 126 - 300 {y=0} {} 100 - 301 {y=1} t1y 50 - 302 {y=0.1} t1y 50 + 300 {y=0} t1y 974 + 301 {y=1} t1y 26 + 302 {y=0.1} t1y 1 400 {x IS NULL} t1x 400 @@ -204,16 +192,17 @@ db eval { # Verify that range queries generate the correct row count estimates # foreach {testid where index rows} { - 500 {x IS NULL AND u='charlie'} t1u 20 - 501 {x=1 AND u='charlie'} t1x 5 - 502 {x IS NULL} {} 100 - 503 {x=1} t1x 50 - 504 {x IS NOT NULL} t1x 25 + 500 {x IS NULL AND u='charlie'} t1u 17 + 501 {x=1 AND u='charlie'} t1x 1 + 502 {x IS NULL} t1x 995 + 503 {x=1} t1x 1 + 504 {x IS NOT NULL} t1x 2 505 {+x IS NOT NULL} {} 500 506 {upper(x) IS NOT NULL} {} 500 } { # Verify that the expected index is used with the expected row count +if {$testid==50299} {breakpoint; set sqlite_where_trace 1} do_test analyze5-1.${testid}a { set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] set idx {} @@ -221,6 +210,7 @@ foreach {testid where index rows} { regexp {~([0-9]+) rows} $x all nrow list $idx $nrow } [list $index $rows] +if {$testid==50299} exit # Verify that the same result is achieved regardless of whether or not # the index is used diff --git a/test/analyze6.test b/test/analyze6.test index b090b5b0..74b7ec79 100644 --- a/test/analyze6.test +++ b/test/analyze6.test @@ -17,7 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat2 { +ifcapable !stat3 { finish_test return } diff --git a/test/analyze7.test b/test/analyze7.test index 4892a223..5bdb04d7 100644 --- a/test/analyze7.test +++ b/test/analyze7.test @@ -82,14 +82,14 @@ do_test analyze7-3.1 { do_test analyze7-3.2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~86 rows)}} -ifcapable stat2 { - # If ENABLE_STAT2 is defined, SQLite comes up with a different estimated +ifcapable stat3 { + # If ENABLE_STAT3 is defined, SQLite comes up with a different estimated # row count for (c=2) than it does for (c=?). do_test analyze7-3.2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} - } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~51 rows)}} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~57 rows)}} } else { - # If ENABLE_STAT2 is not defined, the expected row count for (c=2) is the + # If ENABLE_STAT3 is not defined, the expected row count for (c=2) is the # same as that for (c=?). do_test analyze7-3.2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} @@ -98,12 +98,14 @@ ifcapable stat2 { do_test analyze7-3.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} -do_test analyze7-3.4 { - execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}} -do_test analyze7-3.5 { - execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} -} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +ifcapable {!stat3} { + do_test analyze7-3.4 { + execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}} + do_test analyze7-3.5 { + execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} + } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +} do_test analyze7-3.6 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?) (~1 rows)}} diff --git a/test/analyze8.test b/test/analyze8.test new file mode 100644 index 00000000..f3e2710a --- /dev/null +++ b/test/analyze8.test @@ -0,0 +1,103 @@ +# 2011 August 13 +# +# 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 tests for SQLite library. The focus of the tests +# in this file is testing the capabilities of sqlite_stat3. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !stat3 { + finish_test + return +} + +set testprefix analyze8 + +proc eqp {sql {db db}} { + uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db +} + +# Scenario: +# +# Two indices. One has mostly singleton entries, but for a few +# values there are hundreds of entries. The other has 10-20 +# entries per value. +# +# Verify that the query planner chooses the first index for the singleton +# entries and the second index for the others. +# +do_test 1.0 { + db eval { + CREATE TABLE t1(a,b,c,d); + CREATE INDEX t1a ON t1(a); + CREATE INDEX t1b ON t1(b); + CREATE INDEX t1c ON t1(c); + } + for {set i 0} {$i<1000} {incr i} { + if {$i%2==0} {set a $i} {set a [expr {($i%8)*100}]} + set b [expr {$i/10}] + set c [expr {$i/8}] + set c [expr {$c*$c*$c}] + db eval {INSERT INTO t1 VALUES($a,$b,$c,$i)} + } + db eval {ANALYZE} +} {} + +# The a==100 comparison is expensive because there are many rows +# with a==100. And so for those cases, choose the t1b index. +# +# Buf ro a==99 and a==101, there are far fewer rows so choose +# the t1a index. +# +do_test 1.1 { + eqp {SELECT * FROM t1 WHERE a=100 AND b=55} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}} +do_test 1.2 { + eqp {SELECT * FROM t1 WHERE a=99 AND b=55} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +do_test 1.3 { + eqp {SELECT * FROM t1 WHERE a=101 AND b=55} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +do_test 1.4 { + eqp {SELECT * FROM t1 WHERE a=100 AND b=56} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}} +do_test 1.5 { + eqp {SELECT * FROM t1 WHERE a=99 AND b=56} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +do_test 1.6 { + eqp {SELECT * FROM t1 WHERE a=101 AND b=56} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}} +do_test 2.1 { + eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54} +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b? AND b? AND c? AND c$SQLITE_MAX_PAGE_SIZE} continue do_test filefmt-1.5.$pagesize.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db db eval "PRAGMA auto_vacuum=OFF" db eval "PRAGMA page_size=$pagesize" @@ -105,7 +105,7 @@ do_test filefmt-1.7 { ifcapable pager_pragmas { do_test filefmt-1.8 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db db eval {PRAGMA page_size=512; CREATE TABLE t1(x)} db close @@ -125,7 +125,7 @@ ifcapable pager_pragmas { # always derives this from the size of the file. # db close -file delete -force test.db +forcedelete test.db set a_string_counter 1 proc a_string {n} { @@ -157,7 +157,7 @@ integrity_check filefmt-2.1.5 do_test filefmt-2.1.6 { hexio_read test.db 28 4 } {00000010} db close -file delete -force test.db +forcedelete test.db sqlite3 db test.db db func a_string a_string diff --git a/test/fkey_malloc.test b/test/fkey_malloc.test index 05a2a4f4..4a36f5f3 100644 --- a/test/fkey_malloc.test +++ b/test/fkey_malloc.test @@ -68,7 +68,7 @@ proc catch_fk_error {zSql} { if {[string match {*foreign key*} $msg]} { return "" } - if {$msg eq "out of memory"} { + if {$msg eq "out of memory" || $msg eq "constraint failed"} { error 1 } error $msg diff --git a/test/fts-9fd058691.test b/test/fts-9fd058691.test new file mode 100644 index 00000000..b228482d --- /dev/null +++ b/test/fts-9fd058691.test @@ -0,0 +1,59 @@ +# 2011 October 13 +# +# 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 the FTS SQLite module. +# +# This file implements tests to verify that ticket [9fd058691] has been +# fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +set ::testprefix fts3-9fd058691 + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE fts USING fts3( tags TEXT); + INSERT INTO fts (tags) VALUES ('tag1'); + SELECT * FROM fts WHERE tags MATCH 'tag1'; +} {tag1} + +do_test 1.1 { + db close + sqlite3 db test.db + execsql { + UPDATE fts SET tags = 'tag1' WHERE rowid = 1; + SELECT * FROM fts WHERE tags MATCH 'tag1'; + } +} {tag1} + +db close +forcedelete test.db +sqlite3 db test.db + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE fts USING fts3(tags TEXT); + INSERT INTO fts (docid, tags) VALUES (1, 'tag1'); + INSERT INTO fts (docid, tags) VALUES (2, NULL); + INSERT INTO fts (docid, tags) VALUES (3, 'three'); +} {} + +do_test 2.1 { + execsql { + UPDATE fts SET tags = 'two' WHERE rowid = 2; + SELECT * FROM fts WHERE tags MATCH 'two'; + } +} {two} + +finish_test diff --git a/test/fts1j.test b/test/fts1j.test index 5ff0d0ed..4dac22ab 100644 --- a/test/fts1j.test +++ b/test/fts1j.test @@ -19,8 +19,8 @@ ifcapable !fts1 { } # Clean up anything left over from a previous pass. -file delete -force test2.db -file delete -force test2.db-journal +forcedelete test2.db +forcedelete test2.db-journal sqlite3 db2 test2.db db eval { @@ -84,6 +84,6 @@ do_test fts1j-1.3 { catch {db eval {DETACH DATABASE two}} catch {db2 close} -file delete -force test2.db +forcedelete test2.db finish_test diff --git a/test/fts1o.test b/test/fts1o.test index 92666c6f..61fd74ca 100644 --- a/test/fts1o.test +++ b/test/fts1o.test @@ -95,7 +95,7 @@ do_test fts1o-3.6 { # Test that it is possible to rename an fts1 table in an attached # database. # -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal do_test fts1o-4.1 { execsql { diff --git a/test/fts2j.test b/test/fts2j.test index b8a89b20..a8a2c07c 100644 --- a/test/fts2j.test +++ b/test/fts2j.test @@ -19,8 +19,8 @@ ifcapable !fts2 { } # Clean up anything left over from a previous pass. -file delete -force test2.db -file delete -force test2.db-journal +forcedelete test2.db +forcedelete test2.db-journal sqlite3 db2 test2.db db eval { @@ -84,6 +84,6 @@ do_test fts2j-1.3 { catch {db eval {DETACH DATABASE two}} catch {db2 close} -file delete -force test2.db +forcedelete test2.db finish_test diff --git a/test/fts2o.test b/test/fts2o.test index 5a33c455..63e71b95 100644 --- a/test/fts2o.test +++ b/test/fts2o.test @@ -109,7 +109,7 @@ do_test fts2o-2.12 { # be run on an initially empty db. # db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db do_test fts2o-3.1 { @@ -134,7 +134,7 @@ do_test fts2o-3.2 { # Test that it is possible to rename an fts2 table in an attached # database. # -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal do_test fts2o-3.1 { execsql { diff --git a/test/fts3aj.test b/test/fts3aj.test index 60d26c02..f3d46f2a 100644 --- a/test/fts3aj.test +++ b/test/fts3aj.test @@ -19,8 +19,8 @@ ifcapable !fts3 { } # Clean up anything left over from a previous pass. -file delete -force test2.db -file delete -force test2.db-journal +forcedelete test2.db +forcedelete test2.db-journal sqlite3 db2 test2.db db eval { @@ -84,6 +84,6 @@ do_test fts3aj-1.3 { catch {db eval {DETACH DATABASE two}} catch {db2 close} -file delete -force test2.db +forcedelete test2.db finish_test diff --git a/test/fts3ao.test b/test/fts3ao.test index cd9df01e..786667a7 100644 --- a/test/fts3ao.test +++ b/test/fts3ao.test @@ -111,7 +111,7 @@ do_test fts3ao-2.12 { # be run on an initially empty db. # db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db do_test fts3ao-3.1 { @@ -136,7 +136,7 @@ do_test fts3ao-3.2 { # Test that it is possible to rename an fts3 table in an attached # database. # -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal do_test fts3ao-3.1 { execsql { @@ -200,6 +200,9 @@ do_test fts3ao-4.7 { SELECT * FROM t5; } } {{the quick brown fox} {jumped over the} {lazy dog}} +do_execsql_test fts3ao-4.8 { + SELECT snippet(t5, '[', ']') FROM t5 WHERE t5 MATCH 'the' +} {{[the] quick brown fox} {jumped over [the]}} # Test that it is possible to rename an FTS4 table. Renaming an FTS4 table # involves renaming the extra %_docsize and %_stat tables. diff --git a/test/fts3auto.test b/test/fts3auto.test index 484fd6ac..1c58a172 100644 --- a/test/fts3auto.test +++ b/test/fts3auto.test @@ -107,15 +107,17 @@ proc do_fts3query_test {tn args} { " $matchinfo_asc } -# fts3_make_deferrable TABLE TOKEN +# fts3_make_deferrable TABLE TOKEN ?NROW? # -proc fts3_make_deferrable {tbl token} { +proc fts3_make_deferrable {tbl token {nRow 0}} { set stmt [sqlite3_prepare db "SELECT * FROM $tbl" -1 dummy] set name [sqlite3_column_name $stmt 0] sqlite3_finalize $stmt - set nRow [db one "SELECT count(*) FROM $tbl"] + if {$nRow==0} { + set nRow [db one "SELECT count(*) FROM $tbl"] + } set pgsz [db one "PRAGMA page_size"] execsql BEGIN for {set i 0} {$i < ($nRow * $pgsz * 1.2)/100} {incr i} { @@ -653,6 +655,50 @@ foreach {tn pending create} { catchsql { COMMIT } } +foreach {tn create} { + 1 "fts4(x)" + 2 "fts4(x, order=DESC)" +} { + execsql [subst { + DROP TABLE IF EXISTS t1; + CREATE VIRTUAL TABLE t1 USING $create; + }] + + foreach {x} { + "F E N O T K X V A X I E X A P G Q V H U" + "R V A E T C V Q N I E L O N U G J K L U" + "U Y I G W M V F J L X I D C H F P J Q B" + "S G D Z X R P G S S Y B K A S G A I L L" + "L S I C H T Z S R Q P R N K J X L F M J" + "C C C D P X B Z C M A D A C X S B T X V" + "W Y J M D R G V R K B X S A W R I T N C" + "P K L W T M S P O Y Y V V O E H Q A I R" + "C D Y I C Z F H J C O Y A Q F L S B D K" + "P G S C Y C Y V I M B D S Z D D Y W I E" + "Z K Z U E E S F Y X T U A L W O U J C Q" + "P A T Z S W L P L Q V Y Y I P W U X S S" + "I U I H U O F Z F R H R F T N D X A G M" + "N A B M S H K X S O Y D T X S B R Y H Z" + "L U D A S K I L S V Z J P U B E B Y H M" + } { + execsql { INSERT INTO t1 VALUES($x) } + } + + # Add extra documents to the database such that token "B" will be considered + # deferrable if considering the other tokens means that 2 or fewer documents + # will be loaded into memory. + # + fts3_make_deferrable t1 B 2 + + # B is not deferred in either of the first two tests below, since filtering + # on "M" or "D" returns 10 documents or so. But filtering on "M * D" only + # returns 2, so B is deferred in this case. + # + do_fts3query_test 7.$tn.1 t1 {"M B"} + do_fts3query_test 7.$tn.2 t1 {"B D"} + do_fts3query_test 7.$tn.3 -deferred B t1 {"M B D"} +} + set sqlite_fts3_enable_parentheses $sfep finish_test diff --git a/test/fts3d.test b/test/fts3d.test index 715980d8..1ae992b3 100644 --- a/test/fts3d.test +++ b/test/fts3d.test @@ -304,4 +304,57 @@ do_test fts3d-5.1 { } } {{Index already optimal} 2 0} + +# ALTER TABLE RENAME should work regardless of the database encoding. +# +do_test fts3d-6.0 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA encoding=UTF8; + CREATE VIRTUAL TABLE fts USING fts3(a,b,c); + SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; + } +} {fts_content fts_segdir fts_segments} +do_test fts3d-6.1 { + db eval { + ALTER TABLE fts RENAME TO xyz; + SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; + } +} {xyz_content xyz_segdir xyz_segments} +do_test fts3d-6.2 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA encoding=UTF16le; + CREATE VIRTUAL TABLE fts USING fts3(a,b,c); + SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; + } +} {fts_content fts_segdir fts_segments} +do_test fts3d-6.3 { + db eval { + ALTER TABLE fts RENAME TO xyz; + SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; + } +} {xyz_content xyz_segdir xyz_segments} +do_test fts3d-6.4 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA encoding=UTF16be; + CREATE VIRTUAL TABLE fts USING fts3(a,b,c); + SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; + } +} {fts_content fts_segdir fts_segments} +do_test fts3d-6.5 { + db eval { + ALTER TABLE fts RENAME TO xyz; + SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1; + } +} {xyz_content xyz_segdir xyz_segments} + + finish_test diff --git a/test/fts3defer.test b/test/fts3defer.test index 4bc0b0a7..bc50874e 100644 --- a/test/fts3defer.test +++ b/test/fts3defer.test @@ -426,6 +426,18 @@ foreach {tn setup} { SELECT rowid FROM t1 WHERE t1 MATCH '"jk xduvfhk" OR "zm azavwm"' } {8 15 26 92 96} } + + if {$tn>1} { + # These tests will not work with $tn==1, as in this case table t1 is + # created using FTS3. The ^ syntax is only available with FTS4 tables. + # + do_select_test 7.1 { + SELECT rowid FROM t1 WHERE t1 MATCH '^zm mjpavjuhw' + } {56 62} + do_select_test 7.2 { + SELECT rowid FROM t1 WHERE t1 MATCH '^azavwm zm' + } {43} + } } set testprefix fts3defer @@ -449,5 +461,33 @@ do_execsql_test 3.3 { SELECT count(*) FROM x1 WHERE x1 MATCH '"d e f"' } {16} +# At one point the following was causing a floating-point exception. +# +do_execsql_test 4.1 { + CREATE VIRTUAL TABLE x2 USING FTS4(x); + BEGIN; + INSERT INTO x2 VALUES('m m m m m m m m m m m m m m m m m m m m m m m m m m'); + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 SELECT * FROM x2; + INSERT INTO x2 VALUES('a b c d e f g h i j k l m n o p q r s t u v w x y m'); + COMMIT; +} +do_execsql_test 4.2 { + SELECT * FROM x2 WHERE x2 MATCH 'a b c d e f g h i j k l m n o p q r s'; +} {{a b c d e f g h i j k l m n o p q r s t u v w x y m}} + finish_test diff --git a/test/fts3drop.test b/test/fts3drop.test new file mode 100644 index 00000000..8b76eafe --- /dev/null +++ b/test/fts3drop.test @@ -0,0 +1,61 @@ +# 2011 October 29 +# +# 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 the FTS3 module. More specifically, +# that DROP TABLE commands can co-exist with savepoints inside transactions. +# See ticket [48f299634a] for details. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts3drop + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE f1 USING fts3; + INSERT INTO f1 VALUES('a b c'); +} + +do_execsql_test 1.2 { + BEGIN; + INSERT INTO f1 VALUES('d e f'); + SAVEPOINT one; + INSERT INTO f1 VALUES('g h i'); + DROP TABLE f1; + ROLLBACK TO one; + COMMIT; +} + +do_execsql_test 1.3 { + SELECT * FROM f1; +} {{a b c} {d e f}} + +do_execsql_test 1.4 { + BEGIN; + INSERT INTO f1 VALUES('g h i'); + SAVEPOINT one; + INSERT INTO f1 VALUES('j k l'); + DROP TABLE f1; + RELEASE one; + ROLLBACK; +} + +do_execsql_test 1.5 { + SELECT * FROM f1; +} {{a b c} {d e f}} + +finish_test diff --git a/test/fts3fault.test b/test/fts3fault.test index 2dd7bbbc..ab82daa9 100644 --- a/test/fts3fault.test +++ b/test/fts3fault.test @@ -18,8 +18,6 @@ set ::testprefix fts3fault # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } -if 1 { - # Test error handling in the sqlite3Fts3Init() function. This is the # function that registers the FTS3 module and various support functions # with SQLite. @@ -146,7 +144,8 @@ do_faultsim_test 7.2 -prep { execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, matchinfo=fs3) } } -test { faultsim_test_result {1 {unrecognized matchinfo: fs3}} \ - {1 {vtable constructor failed: t1}} + {1 {vtable constructor failed: t1}} \ + {1 {SQL logic error or missing database}} } do_faultsim_test 7.3 -prep { faultsim_delete_and_reopen @@ -154,9 +153,8 @@ do_faultsim_test 7.3 -prep { execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, matchnfo=fts3) } } -test { faultsim_test_result {1 {unrecognized parameter: matchnfo=fts3}} \ - {1 {vtable constructor failed: t1}} -} - + {1 {vtable constructor failed: t1}} \ + {1 {SQL logic error or missing database}} } proc mit {blob} { diff --git a/test/fts3fault2.test b/test/fts3fault2.test index fb877737..0178ed27 100644 --- a/test/fts3fault2.test +++ b/test/fts3fault2.test @@ -82,4 +82,53 @@ do_faultsim_test 2.1 -prep { faultsim_test_result {0 {a * 1 1 a 0 1 1 b * 1 1 b 0 1 1 c * 1 1 c 0 1 1 x * 1 1 x 1 1 1 y * 1 1 y 1 1 1 z * 1 1 z 1 1 1}} } +do_faultsim_test 3.0 -faults oom* -prep { + faultsim_delete_and_reopen + db eval { CREATE TABLE 'xx yy'(a, b); } +} -body { + execsql { + CREATE VIRTUAL TABLE tt USING fts4(content="xx yy"); + } +} -test { + faultsim_test_result {0 {}} +} + +do_faultsim_test 3.1 -faults oom* -prep { + faultsim_delete_and_reopen + db func zip zip + db func unzip unzip +} -body { + execsql { + CREATE VIRTUAL TABLE tt USING fts4(compress=zip, uncompress=unzip); + } +} -test { + faultsim_test_result {0 {}} +} + +do_test 4.0 { + faultsim_delete_and_reopen + execsql { + CREATE VIRTUAL TABLE ft USING fts4(a, b); + INSERT INTO ft VALUES('U U T C O', 'F N D E S'); + INSERT INTO ft VALUES('P H X G B', 'I D M R U'); + INSERT INTO ft VALUES('P P X D M', 'Y V N T C'); + INSERT INTO ft VALUES('Z L Q O W', 'D F U N Q'); + INSERT INTO ft VALUES('A J D U P', 'C H M Q E'); + INSERT INTO ft VALUES('P S A O H', 'S Z C W D'); + INSERT INTO ft VALUES('T B N L W', 'C A K T I'); + INSERT INTO ft VALUES('K E Z L O', 'L L Y C E'); + INSERT INTO ft VALUES('C R E S V', 'Q V F W P'); + INSERT INTO ft VALUES('S K H G W', 'R W Q F G'); + } + faultsim_save_and_close +} {} +do_faultsim_test 4.1 -prep { + faultsim_restore_and_reopen + db eval {SELECT * FROM sqlite_master} +} -body { + execsql { INSERT INTO ft(ft) VALUES('rebuild') } +} -test { + faultsim_test_result {0 {}} +} + finish_test diff --git a/test/fts3first.test b/test/fts3first.test new file mode 100644 index 00000000..673f818d --- /dev/null +++ b/test/fts3first.test @@ -0,0 +1,163 @@ +# 2011 October 18 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl + +ifcapable !fts3 { + finish_test + return +} + +set testprefix fts3first + +proc lreverse {L} { + set res [list] + for {set ii [expr [llength $L]-1]} {$ii>=0} {incr ii -1} { + lappend res [lindex $L $ii] + } + set res +} + +proc mit {blob} { + set scan(littleEndian) i* + set scan(bigEndian) I* + binary scan $blob $scan($::tcl_platform(byteOrder)) r + return $r +} +db func mit mit + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE x1 USING FTS4(a, b, c); + INSERT INTO x1(docid,a,b,c) VALUES(0, 'K H D S T', 'V M N Y K', 'S Z N Q S'); + INSERT INTO x1(docid,a,b,c) VALUES(1, 'K N J L W', 'S Z W J Q', 'D U W S E'); + INSERT INTO x1(docid,a,b,c) VALUES(2, 'B P M O I', 'R P H W S', 'R J L L E'); + INSERT INTO x1(docid,a,b,c) VALUES(3, 'U R Q M L', 'M J K A V', 'Q W J T J'); + INSERT INTO x1(docid,a,b,c) VALUES(4, 'N J C Y N', 'R U D X V', 'B O U A Q'); + INSERT INTO x1(docid,a,b,c) VALUES(5, 'Q L X L U', 'I F N X S', 'U Q A N Y'); + INSERT INTO x1(docid,a,b,c) VALUES(6, 'M R G U T', 'U V I Q P', 'X Y D L S'); + INSERT INTO x1(docid,a,b,c) VALUES(7, 'D Y P O I', 'X J P K R', 'V O T H V'); + INSERT INTO x1(docid,a,b,c) VALUES(8, 'R Y D L R', 'U U E S J', 'N W L M R'); + INSERT INTO x1(docid,a,b,c) VALUES(9, 'Z P F N P', 'W A X D U', 'V A E Q A'); + INSERT INTO x1(docid,a,b,c) VALUES(10, 'Q I A Q M', 'N D K H C', 'A H T Q Z'); + INSERT INTO x1(docid,a,b,c) VALUES(11, 'T E R Q B', 'C I B C B', 'F Z U W R'); + INSERT INTO x1(docid,a,b,c) VALUES(12, 'E S V U W', 'T P F W H', 'A M D J Q'); + INSERT INTO x1(docid,a,b,c) VALUES(13, 'X S B X Y', 'U D N D P', 'X Z Y G F'); + INSERT INTO x1(docid,a,b,c) VALUES(14, 'K H A B L', 'S R C C Z', 'D W E H J'); + INSERT INTO x1(docid,a,b,c) VALUES(15, 'C E U C C', 'W F M N M', 'T Z U X T'); + INSERT INTO x1(docid,a,b,c) VALUES(16, 'Q G C G H', 'H N N B H', 'B Q I H Y'); + INSERT INTO x1(docid,a,b,c) VALUES(17, 'Q T S K B', 'W B D Y N', 'V J P E C'); + INSERT INTO x1(docid,a,b,c) VALUES(18, 'A J M O Q', 'L G Y Y A', 'G N M R N'); + INSERT INTO x1(docid,a,b,c) VALUES(19, 'T R Y P Y', 'N V Y B X', 'L Z T N T'); + + CREATE VIRTUAL TABLE x2 USING FTS4(a, b, c, order=DESC); + INSERT INTO x2(docid, a, b, c) SELECT docid, a, b, c FROM x1; +} + + +# Test queries. +# +foreach x {1 2} { + foreach {tn match res} { + 1 "^K" {0 1 14} + 2 "^S" {0 1 14} + 3 "^W" {9 15 17} + 4 "^J" {} + 5 "^E" {12} + 6 "V ^-E" {0 3 4 6 7 9 17 19} + 7 "V -^E" {0 3 4 6 7 9 17 19} + 8 "^-E V" {0 3 4 6 7 9 17 19} + 9 "-^E V" {0 3 4 6 7 9 17 19} + 10 "V" {0 3 4 6 7 9 12 17 19} + + 11 {"^K H"} {0 14} + 12 {"K H"} {0 10 14} + 13 {"K ^H"} {} + } { + set rev [lreverse $res] + do_execsql_test 1.$x.$tn.1 {SELECT docid FROM x1 WHERE x1 MATCH $match} $res + do_execsql_test 1.$x.$tn.2 {SELECT docid FROM x2 WHERE x2 MATCH $match} $rev + } + + do_execsql_test 1.$x.[expr $tn+1] { + INSERT INTO x1(x1) VALUES('optimize'); + INSERT INTO x2(x2) VALUES('optimize'); + } {} +} + +# Test the snippet() function. +# +foreach {tn match res} { + 1 {^K} {{[K] H D S T} {[K] N J L W} {[K] H A B L}} + 2 {^X} {{[X] Y D L S} {[X] J P K R} {[X] S B X Y}} + 3 {^X Y} {{[X] [Y] D L S} {D [Y] P O I...[X] J P K R} {[X] S B X [Y]}} +} { + set rev [lreverse $res] + + do_execsql_test 1.3.$tn.1 { + SELECT snippet(x1, '[', ']', '...') FROM x1 WHERE x1 MATCH $match + } $res + + do_execsql_test 1.3.$tn.2 { + SELECT snippet(x2, '[', ']', '...') FROM x2 WHERE x2 MATCH $match + } $rev +} + +# Test matchinfo(). +# +foreach {tn match res} { + 1 {^K} { + {1 3 3 0 0 0 0 0 0} + {1 3 3 0 0 0 0 0 0} + {1 3 3 0 0 0 0 0 0} + } + 2 {^X} { + {0 1 1 0 1 1 1 2 2} + {0 1 1 1 1 1 0 2 2} + {1 1 1 0 1 1 1 2 2} + } + 3 {^X Y} { + {0 1 1 0 1 1 1 2 2 0 6 5 0 5 4 1 4 4} + {0 1 1 1 1 1 0 2 2 1 6 5 0 5 4 0 4 4} + {1 1 1 0 1 1 1 2 2 1 6 5 0 5 4 1 4 4} + } +} { + set rev [lreverse $res] + + do_execsql_test 1.3.$tn.1 { + SELECT mit(matchinfo(x1, 'x')) FROM x1 WHERE x1 MATCH $match + } $res + do_execsql_test 1.3.$tn.2 { + SELECT mit(matchinfo(x2, 'x')) FROM x2 WHERE x2 MATCH $match + } $rev +} + +# Test that ^ is ignored for FTS3 tables. +# +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE x3 USING fts3; + INSERT INTO x3 VALUES('A B C'); + INSERT INTO x3 VALUES('B A C'); + + CREATE VIRTUAL TABLE x4 USING fts4; + INSERT INTO x4 VALUES('A B C'); + INSERT INTO x4 VALUES('B A C'); +} + +do_execsql_test 2.2.1 { + SELECT * FROM x3 WHERE x3 MATCH '^A'; +} {{A B C} {B A C}} +do_execsql_test 2.2.2 { + SELECT * FROM x4 WHERE x4 MATCH '^A'; +} {{A B C}} + +finish_test diff --git a/test/fts3malloc.test b/test/fts3malloc.test index 932ea098..7eeee7fe 100644 --- a/test/fts3malloc.test +++ b/test/fts3malloc.test @@ -294,6 +294,7 @@ do_write_test fts3_malloc-5.1 ft_content { do_test fts3_malloc-5.2 { execsql { CREATE VIRTUAL TABLE ft8 USING fts3(x, tokenize porter) } } {} + do_write_test fts3_malloc-5.3 ft_content { INSERT INTO ft8 VALUES('short alongertoken reallyquitealotlongerimeanit andthistokenisjustsolongthatonemightbeforgivenforimaginingthatitwasmerelyacontrivedexampleandnotarealtoken') } diff --git a/test/fts3matchinfo.test b/test/fts3matchinfo.test index 40366b6a..0e888580 100644 --- a/test/fts3matchinfo.test +++ b/test/fts3matchinfo.test @@ -19,6 +19,7 @@ source $testdir/tester.tcl ifcapable !fts3 { finish_test ; return } set testprefix fts3matchinfo +set sqlite_fts3_enable_parentheses 0 proc mit {blob} { set scan(littleEndian) i* @@ -57,6 +58,9 @@ do_catchsql_test 2.0 { do_catchsql_test 2.1 { CREATE VIRTUAL TABLE x2 USING fts4(mtchinfo=fts3); } {1 {unrecognized parameter: mtchinfo=fts3}} +do_catchsql_test 2.2 { + CREATE VIRTUAL TABLE x2 USING fts4(matchinfo=fts5); +} {1 {unrecognized matchinfo: fts5}} # Check that with fts3, the "=" character is permitted in column definitions. # @@ -224,6 +228,18 @@ do_matchinfo_test 4.1.3 t4 {t4 MATCH 'a b'} { s {{2 0} {0 2}} } do_matchinfo_test 4.1.4 t4 {t4 MATCH '"a b" c'} { s {{2 0} {0 2}} } do_matchinfo_test 4.1.5 t4 {t4 MATCH 'a "b c"'} { s {{2 0} {0 2}} } do_matchinfo_test 4.1.6 t4 {t4 MATCH 'd d'} { s {{1 0} {0 1}} } +do_matchinfo_test 4.1.7 t4 {t4 MATCH 'f OR abcd'} { + x { + {0 1 1 1 1 1 0 0 0 0 0 0} + {1 1 1 0 1 1 0 0 0 0 0 0} + } +} +do_matchinfo_test 4.1.8 t4 {t4 MATCH 'f -abcd'} { + x { + {0 1 1 1 1 1} + {1 1 1 0 1 1} + } +} do_execsql_test 4.2.0 { CREATE VIRTUAL TABLE t5 USING fts4; diff --git a/test/fts3prefix.test b/test/fts3prefix.test index f5e31f32..e7c197da 100644 --- a/test/fts3prefix.test +++ b/test/fts3prefix.test @@ -200,4 +200,14 @@ do_execsql_test 4.6 { SELECT * FROM t3 WHERE t3 MATCH 'one*' } {{one two three}} +#------------------------------------------------------------------------- +# Syntax tests. +# +do_catchsql_test 5.1 { + CREATE VIRTUAL TABLE t4 USING fts4(prefix="abc"); +} {1 {error parsing prefix parameter: abc}} +do_catchsql_test 5.2 { + CREATE VIRTUAL TABLE t4 USING fts4(prefix=""); +} {0 {}} + finish_test diff --git a/test/fts3snippet.test b/test/fts3snippet.test index 359a87c6..b8646cdf 100644 --- a/test/fts3snippet.test +++ b/test/fts3snippet.test @@ -131,7 +131,7 @@ foreach {DO_MALLOC_TEST enc} { } { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 db eval "PRAGMA encoding = \"$enc\"" diff --git a/test/fts3sort.test b/test/fts3sort.test index ce5b5df7..be756043 100644 --- a/test/fts3sort.test +++ b/test/fts3sort.test @@ -138,6 +138,8 @@ foreach {tn param res} { 3 "order=dec" {1 {unrecognized order: dec}} 4 "order=xxx, order=asc" {1 {unrecognized order: xxx}} 5 "order=desc, order=asc" {0 {}} + 6 "order=xxxx, order=asc" {1 {unrecognized order: xxxx}} + 7 "order=desk" {1 {unrecognized order: desk}} } { execsql { DROP TABLE IF EXISTS t1 } do_catchsql_test 2.1.$tn " @@ -157,6 +159,27 @@ do_execsql_test 2.2 { do_execsql_test 2.3 { SELECT docid FROM t2 WHERE t2 MATCH 'aa'; } {3 1} +do_execsql_test 2.4 { + SELECT docid FROM t2 WHERE t2 MATCH 'aa' ORDER BY content; +} {1 3} + +#------------------------------------------------------------------------- +# Test that ticket [56be976859] has been fixed. +# +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE t3 USING fts4(x, order=DESC); + INSERT INTO t3(docid, x) VALUES(113382409004785664, 'aa'); + INSERT INTO t3(docid, x) VALUES(1, 'ab'); + SELECT rowid FROM t3 WHERE x MATCH 'a*' ORDER BY docid DESC; +} {113382409004785664 1} +do_execsql_test 3.2 { + CREATE VIRTUAL TABLE t4 USING fts4(x); + INSERT INTO t4(docid, x) VALUES(-113382409004785664, 'aa'); + INSERT INTO t4(docid, x) VALUES(1, 'ab'); + SELECT rowid FROM t4 WHERE x MATCH 'a*'; +} {-113382409004785664 1} + + finish_test diff --git a/test/fts4aa.test b/test/fts4aa.test index 1131df3b..c5693317 100644 --- a/test/fts4aa.test +++ b/test/fts4aa.test @@ -1686,7 +1686,7 @@ foreach {q r} [array get fts4aa_res] { # do_test fts4aa-3.0 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db db eval { PRAGMA page_size=65536; diff --git a/test/fts4content.test b/test/fts4content.test new file mode 100644 index 00000000..025b600b --- /dev/null +++ b/test/fts4content.test @@ -0,0 +1,501 @@ +# 2011 October 03 +# +# 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 the content=xxx FTS4 option. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix fts4content + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +#------------------------------------------------------------------------- +# Test organization: +# +# 1.* - Warm-body tests. +# +# 2.* - Querying a content=xxx FTS table. +# +# 3.* - Writing to a content=xxx FTS table. +# +# 4.* - The "INSERT INTO fts(fts) VALUES('rebuild')" command. +# +# 5.* - Check that CREATE TABLE, DROP TABLE and ALTER TABLE correctly +# ignore any %_content table when used with the content=xxx option. +# +# 6.* - Test the effects of messing with the schema of table xxx after +# creating a content=xxx FTS index. +# +# 7.* - Test that if content=xxx is specified and table xxx does not +# exist, the FTS table can still be used for INSERT and some +# SELECT statements. +# + +do_execsql_test 1.1.1 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES('w x', 'x y', 'y z'); + CREATE VIRTUAL TABLE ft1 USING fts4(content=t1); +} + +do_execsql_test 1.1.2 { + PRAGMA table_info(ft1); +} { + 0 a {} 0 {} 0 + 1 b {} 0 {} 0 + 2 c {} 0 {} 0 +} + +do_execsql_test 1.1.3 { SELECT *, rowid FROM ft1 } {{w x} {x y} {y z} 1} +do_execsql_test 1.1.4 { SELECT a, c FROM ft1 WHERE rowid=1 } {{w x} {y z}} + +do_execsql_test 1.1.5 { INSERT INTO ft1(ft1) VALUES('rebuild') } {} +do_execsql_test 1.1.6 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'x' } {1} +do_execsql_test 1.1.7 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'a' } {} + +do_execsql_test 1.2.1 { + DROP TABLE ft1; + CREATE VIRTUAL TABLE ft1 USING fts4(content=t1, b); + PRAGMA table_info(ft1); +} { + 0 b {} 0 {} 0 +} +do_execsql_test 1.2.2 { + SELECT *, rowid FROM ft1 +} {{x y} 1} + +#------------------------------------------------------------------------- +# The following block of tests - 2.* - test that a content=xxx FTS table +# can be queried. Also tested are cases where rows identified in the FTS +# are missing from the content table, and cases where the index is +# inconsistent with the content table. +# +do_execsql_test 2.0 { + CREATE TABLE t2(x); + INSERT INTO t2 VALUES('O S W W F U C R Q I C N P Z Y Y E Y Y E'); -- 1 + INSERT INTO t2 VALUES('Y X U V L B E H Y J C Y A I A P V F V K'); -- 2 + INSERT INTO t2 VALUES('P W I N J H I I N I F B K D U Q B Z S F'); -- 3 + INSERT INTO t2 VALUES('N R O R H J R H G M D I U U B O M P A U'); -- 4 + INSERT INTO t2 VALUES('Y O V O G T P N G T N F I V B U M J M G'); -- 5 + INSERT INTO t2 VALUES('J O B N K N E C H Z R K J O U G M K L S'); -- 6 + INSERT INTO t2 VALUES('S Z S R I Q U A P W R X H K C Z U L S P'); -- 7 + INSERT INTO t2 VALUES('J C H N R C K R V N M O F Z M Z A I H W'); -- 8 + INSERT INTO t2 VALUES('O Y G I S J U U W O D Z F J K N R P R L'); -- 9 + INSERT INTO t2 VALUES('B G L K U R U P V X Z I H V R W C Q A S'); -- 10 + INSERT INTO t2 VALUES('T F T J F F Y V F W N X K Q A Y L X W G'); -- 11 + INSERT INTO t2 VALUES('C J U H B Q X L C M M Y E G V F W V Z C'); -- 12 + INSERT INTO t2 VALUES('B W L T F S G X D P H N G M R I O A X I'); -- 13 + INSERT INTO t2 VALUES('N G Y O K Q K Z N M H U J E D H U W R K'); -- 14 + INSERT INTO t2 VALUES('U D T R U Y F J D S J X E H Q G V A S Z'); -- 15 + INSERT INTO t2 VALUES('M I W P J S H R J D Q I C G P C T P H R'); -- 16 + INSERT INTO t2 VALUES('J M N I S L X Q C A B F C B Y D H V R J'); -- 17 + INSERT INTO t2 VALUES('F V Z W J Q L P X Y E W B U Q N H X K T'); -- 18 + INSERT INTO t2 VALUES('R F S R Y O F Q E I E G H C B H R X Y N'); -- 19 + INSERT INTO t2 VALUES('U Q Q Q T E P D M F X P J G H X C Q D L'); -- 20 +} + +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE ft2 USING fts4(content=t2); + INSERT INTO ft2(ft2) VALUES('rebuild'); + + -- Modify the backing table a bit: Row 17 is missing and the contents + -- of row 20 do not match the FTS index contents. + DELETE FROM t2 WHERE rowid = 17; + UPDATE t2 SET x = 'a b c d e f g h i j' WHERE rowid = 20; +} + +foreach {tn match rowidlist} { + 1 {S} {1 3 6 7 9 10 13 15 16 17 19} + 2 {"S R"} {7 19} + 3 {"N K N"} {6} + 4 {"Q Q"} {20} + 5 {"B Y D"} {17} +} { + do_execsql_test 2.2.1.$tn { + SELECT rowid FROM ft2 WHERE ft2 MATCH $match + } $rowidlist + + do_execsql_test 2.2.2.$tn { + SELECT docid FROM ft2 WHERE ft2 MATCH $match + } $rowidlist +} + +foreach {tn match result} { + 1 {"N K N"} {{J O B N K N E C H Z R K J O U G M K L S}} + 2 {"Q Q"} {{a b c d e f g h i j}} + 3 {"B Y D"} {{}} +} { + do_execsql_test 2.3.$tn { + SELECT * FROM ft2 WHERE ft2 MATCH $match + } $result +} + +foreach {tn match result} { + 1 {"N K N"} {{..O B [N] [K] [N] E..}} + 2 {"B Y D"} {{}} + 3 {"Q Q"} {{a [b] [c] [d] e f..}} +} { + do_execsql_test 2.4.$tn { + SELECT snippet(ft2, '[', ']', '..', -1, 6) FROM ft2 WHERE ft2 MATCH $match + } $result +} + +foreach {tn match result} { + 1 {"N K N"} {{0 0 6 1 0 1 8 1 0 2 10 1}} + 2 {"B Y D"} {{}} + 3 {"Q Q"} {{0 0 2 1 0 0 4 1 0 1 4 1 0 1 6 1}} + 4 {"Q D L"} {{}} +} { + do_execsql_test 2.5.$tn { + SELECT offsets(ft2) FROM ft2 WHERE ft2 MATCH $match + } $result +} + +#------------------------------------------------------------------------- +# The following block of tests - 3.* - test that the FTS index can be +# modified by writing to the table. But that this has no effect on the +# content table. +# + +do_execsql_test 3.1 { + CREATE TABLE t3(x, y); + CREATE VIRTUAL TABLE ft3 USING fts4(content=t3); +} + +do_catchsql_test 3.1.1 { + INSERT INTO ft3 VALUES('a b c', 'd e f'); +} {1 {constraint failed}} +do_execsql_test 3.1.2 { + INSERT INTO ft3(docid, x, y) VALUES(21, 'a b c', 'd e f'); + SELECT rowid FROM ft3 WHERE ft3 MATCH '"a b c"'; +} {21} +do_execsql_test 3.1.3 { SELECT * FROM t3 } {} + +# This DELETE does not work, since there is no row in [t3] to base the +# DELETE on. So the SELECT on [ft3] still returns rowid 21. +do_execsql_test 3.1.4 { + DELETE FROM ft3; + SELECT rowid FROM ft3 WHERE ft3 MATCH '"a b c"'; +} {21} + +# If the row is added to [t3] before the DELETE on [ft3], it works. +do_execsql_test 3.1.5 { + INSERT INTO t3(rowid, x, y) VALUES(21, 'a b c', 'd e f'); + DELETE FROM ft3; + SELECT rowid FROM ft3 WHERE ft3 MATCH '"a b c"'; +} {} +do_execsql_test 3.1.6 { SELECT rowid FROM t3 } {21} + +do_execsql_test 3.2.1 { + INSERT INTO ft3(rowid, x, y) VALUES(0, 'R T M S M', 'A F O K H'); + INSERT INTO ft3(rowid, x, y) VALUES(1, 'C Z J O X', 'U S Q D K'); + INSERT INTO ft3(rowid, x, y) VALUES(2, 'N G H P O', 'N O P O C'); + INSERT INTO ft3(rowid, x, y) VALUES(3, 'V H S D R', 'K N G E C'); + INSERT INTO ft3(rowid, x, y) VALUES(4, 'J T R V U', 'U X S L C'); + INSERT INTO ft3(rowid, x, y) VALUES(5, 'N A Y N G', 'X D G P Y'); + INSERT INTO ft3(rowid, x, y) VALUES(6, 'I Q I S P', 'D R O Q B'); + INSERT INTO ft3(rowid, x, y) VALUES(7, 'T K T Z J', 'B W D G O'); + INSERT INTO ft3(rowid, x, y) VALUES(8, 'Y K F X T', 'D F G V G'); + INSERT INTO ft3(rowid, x, y) VALUES(9, 'E L E T L', 'P W N F Z'); + INSERT INTO ft3(rowid, x, y) VALUES(10, 'O G J G X', 'G J F E P'); + INSERT INTO ft3(rowid, x, y) VALUES(11, 'O L N N Z', 'K E Z F D'); + INSERT INTO ft3(rowid, x, y) VALUES(12, 'R Z M R J', 'X G I M Z'); + INSERT INTO ft3(rowid, x, y) VALUES(13, 'L X N N X', 'R R N S T'); + INSERT INTO ft3(rowid, x, y) VALUES(14, 'F L B J H', 'K W F L C'); + INSERT INTO ft3(rowid, x, y) VALUES(15, 'P E B M V', 'E A A B U'); + INSERT INTO ft3(rowid, x, y) VALUES(16, 'V E C F P', 'L U T V K'); + INSERT INTO ft3(rowid, x, y) VALUES(17, 'T N O Z N', 'T P Q X N'); + INSERT INTO ft3(rowid, x, y) VALUES(18, 'V W U W R', 'H O A A V'); + INSERT INTO ft3(rowid, x, y) VALUES(19, 'A H N L F', 'I G H B O'); +} + +foreach {tn match rowidlist} { + 1 "N A" {5 19} + 2 "x:O" {1 2 10 11 17} + 3 "y:O" {0 2 6 7 18 19} +} { + set res [list] + foreach rowid $rowidlist { lappend res $rowid {} {} } + + do_execsql_test 3.2.2.$tn { + SELECT rowid, * FROM ft3 WHERE ft3 MATCH $match + } $res + do_execsql_test 3.2.3.$tn { + SELECT docid, * FROM ft3 WHERE ft3 MATCH $match + } $res +} + +do_execsql_test 3.3.1 { + INSERT INTO t3(rowid, x, y) VALUES(0, 'R T M S M', 'A F O K H'); + INSERT INTO t3(rowid, x, y) VALUES(1, 'C Z J O X', 'U S Q D K'); + INSERT INTO t3(rowid, x, y) VALUES(2, 'N G H P O', 'N O P O C'); + INSERT INTO t3(rowid, x, y) VALUES(3, 'V H S D R', 'K N G E C'); + INSERT INTO t3(rowid, x, y) VALUES(4, 'J T R V U', 'U X S L C'); + INSERT INTO t3(rowid, x, y) VALUES(5, 'N A Y N G', 'X D G P Y'); + UPDATE ft3 SET x = y, y = x; + DELETE FROM t3; +} + +foreach {tn match rowidlist} { + 1 "N A" {5 19} + 2 "x:O" {0 2 10 11 17} + 3 "y:O" {1 2 6 7 18 19} +} { + set res [list] + foreach rowid $rowidlist { lappend res $rowid {} {} } + + do_execsql_test 3.3.2.$tn { + SELECT rowid, * FROM ft3 WHERE ft3 MATCH $match + } $res + do_execsql_test 3.3.3.$tn { + SELECT docid, * FROM ft3 WHERE ft3 MATCH $match + } $res +} + +do_execsql_test 3.3.1 { + INSERT INTO t3(rowid, x, y) VALUES(15, 'P E B M V', 'E A A B U'); + INSERT INTO t3(rowid, x, y) VALUES(16, 'V E C F P', 'L U T V K'); + INSERT INTO t3(rowid, x, y) VALUES(17, 'T N O Z N', 'T P Q X N'); + INSERT INTO t3(rowid, x, y) VALUES(18, 'V W U W R', 'H O A A V'); + INSERT INTO t3(rowid, x, y) VALUES(19, 'A H N L F', 'I G H B O'); + DELETE FROM ft3; +} + +foreach {tn match rowidlist} { + 1 "N A" {5} + 2 "x:O" {0 2 10 11} + 3 "y:O" {1 2 6 7} +} { + set res [list] + foreach rowid $rowidlist { lappend res $rowid {} {} } + + do_execsql_test 3.3.2.$tn { + SELECT rowid, * FROM ft3 WHERE ft3 MATCH $match + } $res + do_execsql_test 3.3.3.$tn { + SELECT docid, * FROM ft3 WHERE ft3 MATCH $match + } $res +} + + +#------------------------------------------------------------------------- +# Test cases 4.* test the 'rebuild' command. On content=xxx and regular +# FTS tables. +# +do_execsql_test 4.0 { + CREATE TABLE t4(x); + CREATE VIRTUAL TABLE ft4 USING fts4(content=t4); + CREATE VIRTUAL TABLE ft4x USING fts4(x); +} + +do_execsql_test 4.1.1 { + INSERT INTO ft4x(ft4x) VALUES('rebuild'); + INSERT INTO ft4(ft4) VALUES('rebuild'); +} {} +do_execsql_test 4.1.2 { + SELECT id, quote(value) FROM ft4_stat +} {0 X'000000'} +do_execsql_test 4.1.3 { + SELECT id, quote(value) FROM ft4x_stat +} {0 X'000000'} + +do_execsql_test 4.2.1 { + INSERT INTO ft4x VALUES('M G M F T'); + INSERT INTO ft4x VALUES('Z Q C A U'); + INSERT INTO ft4x VALUES('N L L V'); + INSERT INTO ft4x VALUES('T F D X D'); + INSERT INTO ft4x VALUES('Z H I S D'); + + SELECT id, quote(value) FROM ft4x_stat +} {0 X'05182B'} + +do_execsql_test 4.2.2 { + INSERT INTO ft4(rowid, x) SELECT rowid, * FROM ft4x; + SELECT id, quote(value) FROM ft4_stat +} {0 X'05182B'} + +do_execsql_test 4.2.3 { + SELECT docid, quote(size) FROM ft4_docsize +} {1 X'05' 2 X'05' 3 X'04' 4 X'05' 5 X'05'} + +do_execsql_test 4.2.4 { + INSERT INTO ft4x(ft4x) VALUES('rebuild'); + SELECT id, quote(value) FROM ft4x_stat; + SELECT docid, quote(size) FROM ft4x_docsize +} {0 X'05182B' 1 X'05' 2 X'05' 3 X'04' 4 X'05' 5 X'05'} + +do_execsql_test 4.2.5 { + INSERT INTO ft4(ft4) VALUES('rebuild'); + SELECT id, quote(value) FROM ft4_stat; + SELECT docid, quote(size) FROM ft4_docsize +} {0 X'000000'} + +do_execsql_test 4.2.6 { + INSERT INTO t4(rowid, x) SELECT rowid, x FROM ft4x; + INSERT INTO ft4(ft4) VALUES('rebuild'); + SELECT id, quote(value) FROM ft4_stat; + SELECT docid, quote(size) FROM ft4_docsize +} {0 X'05182B' 1 X'05' 2 X'05' 3 X'04' 4 X'05' 5 X'05'} + + +#------------------------------------------------------------------------- +# Test cases 5.* test that the following commands do not create/move or +# delete a %_content table when used with a content=xxx FTS table. +# +do_execsql_test 5.1.1 { + CREATE TABLE t5(a, b, c, d); + CREATE VIRTUAL TABLE ft5 USING fts4(content=t5); + SELECT name FROM sqlite_master WHERE name LIKE '%t5%'; +} { + t5 ft5 ft5_segments ft5_segdir + sqlite_autoindex_ft5_segdir_1 ft5_docsize ft5_stat +} +do_execsql_test 5.1.2 { + ALTER TABLE ft5 RENAME TO ft6; + SELECT name FROM sqlite_master WHERE name LIKE '%t5%'; +} { + t5 +} +do_execsql_test 5.1.3 { + SELECT name FROM sqlite_master WHERE name LIKE '%t6%'; +} { + ft6 ft6_segments ft6_segdir + sqlite_autoindex_ft6_segdir_1 ft6_docsize ft6_stat +} +do_execsql_test 5.1.4 { + INSERT INTO t5 VALUES('a', 'b', 'c', 'd'); + INSERT INTO ft6(ft6) VALUES('rebuild'); + SELECT rowid FROM ft6 WHERE ft6 MATCH 'b'; +} {1} +do_execsql_test 5.1.5 { + DROP TABLE ft6; + SELECT * FROM t5; +} {a b c d} +do_execsql_test 5.1.6 { + SELECT name FROM sqlite_master WHERE name LIKE '%t6%'; +} { +} +do_execsql_test 5.1.7 { + CREATE VIRTUAL TABLE ft5 USING fts4(content=t5); + CREATE TABLE t5_content(a, b); + DROP TABLE ft5; + SELECT name FROM sqlite_master WHERE name LIKE '%t5%'; +} { + t5 t5_content +} + +#------------------------------------------------------------------------- +# Test cases 6.* test +# +do_catchsql_test 6.1.1 { + CREATE VIRTUAL TABLE ft7 USING fts4(content=t7); +} {1 {vtable constructor failed: ft7}} + +do_execsql_test 6.2.1 { + CREATE TABLE t7(one, two); + CREATE VIRTUAL TABLE ft7 USING fts4(content=t7); + INSERT INTO t7 VALUES('A B', 'B A'); + INSERT INTO t7 VALUES('C D', 'A A'); + SELECT * FROM ft7; +} { + {A B} {B A} {C D} {A A} +} + +do_catchsql_test 6.2.2 { + DROP TABLE t7; + SELECT * FROM ft7; +} {1 {SQL logic error or missing database}} + +db close +sqlite3 db test.db +do_execsql_test 6.2.3 { + SELECT name FROM sqlite_master WHERE name LIKE '%t7%' +} { + ft7 ft7_segments ft7_segdir sqlite_autoindex_ft7_segdir_1 + ft7_docsize ft7_stat +} +do_catchsql_test 6.2.4 { + SELECT * FROM ft7; +} {1 {vtable constructor failed: ft7}} +do_execsql_test 6.2.5 { + CREATE TABLE t7(x, y); + INSERT INTO t7 VALUES('A B', 'B A'); + INSERT INTO t7 VALUES('C D', 'A A'); + SELECT * FROM ft7; +} { + {A B} {B A} {C D} {A A} +} + +do_execsql_test 6.2.6 { + INSERT INTO ft7(ft7) VALUES('rebuild'); + SELECT rowid FROM ft7 WHERE ft7 MATCH '"A A"'; +} {2} + +do_execsql_test 6.2.7 { + DROP TABLE t7; + CREATE TABLE t7(x); +} +do_catchsql_test 6.2.8 { + SELECT * FROM ft7 WHERE ft7 MATCH '"A A"'; +} {1 {SQL logic error or missing database}} +do_catchsql_test 6.2.9 { + SELECT * FROM ft7 WHERE ft7 MATCH '"A A"'; +} {1 {SQL logic error or missing database}} + +db close +sqlite3 db test.db +do_catchsql_test 6.2.10 { + SELECT rowid FROM ft7 WHERE ft7 MATCH '"A A"'; +} {0 2} +do_catchsql_test 6.2.11 { + SELECT rowid, * FROM ft7 WHERE ft7 MATCH '"A A"'; +} {0 {2 {}}} + +#------------------------------------------------------------------------- +# Test cases 7.* +# +do_execsql_test 7.1.1 { + CREATE VIRTUAL TABLE ft8 USING fts4(content=nosuchtable, x); + INSERT INTO ft8(docid, x) VALUES(13, 'U O N X G'); + INSERT INTO ft8(docid, x) VALUES(14, 'C J J U B'); + INSERT INTO ft8(docid, x) VALUES(15, 'N J Y G X'); + INSERT INTO ft8(docid, x) VALUES(16, 'R Y D O R'); + INSERT INTO ft8(docid, x) VALUES(17, 'I Y T Q O'); +} + +do_execsql_test 7.1.2 { + SELECT docid FROM ft8 WHERE ft8 MATCH 'N'; +} {13 15} + +do_execsql_test 7.2.1 { + CREATE VIRTUAL TABLE ft9 USING fts4(content=, x); + INSERT INTO ft9(docid, x) VALUES(13, 'U O N X G'); + INSERT INTO ft9(docid, x) VALUES(14, 'C J J U B'); + INSERT INTO ft9(docid, x) VALUES(15, 'N J Y G X'); + INSERT INTO ft9(docid, x) VALUES(16, 'R Y D O R'); + INSERT INTO ft9(docid, x) VALUES(17, 'I Y T Q O'); +} +do_execsql_test 7.2.2 { + SELECT docid FROM ft9 WHERE ft9 MATCH 'N'; +} {13 15} +do_execsql_test 7.2.3 { + SELECT name FROM sqlite_master WHERE name LIKE 'ft9_%'; +} {ft9_segments ft9_segdir ft9_docsize ft9_stat} + +do_catchsql_test 7.2.4 { + SELECT * FROM ft9 WHERE ft9 MATCH 'N'; +} {1 {SQL logic error or missing database}} + +finish_test diff --git a/test/func3.test b/test/func3.test index e58d730f..d5a462fe 100644 --- a/test/func3.test +++ b/test/func3.test @@ -17,24 +17,26 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -do_test func3-1.1 { - set destroyed 0 - proc destroy {} { set ::destroyed 1 } - sqlite3_create_function_v2 db f2 -1 any -func f2 -destroy destroy - set destroyed -} 0 -do_test func3-1.2 { - sqlite3_create_function_v2 db f2 -1 utf8 -func f2 - set destroyed -} 0 -do_test func3-1.3 { - sqlite3_create_function_v2 db f2 -1 utf16le -func f2 - set destroyed -} 0 -do_test func3-1.4 { - sqlite3_create_function_v2 db f2 -1 utf16be -func f2 - set destroyed -} 1 +ifcapable utf16 { + do_test func3-1.1 { + set destroyed 0 + proc destroy {} { set ::destroyed 1 } + sqlite3_create_function_v2 db f2 -1 any -func f2 -destroy destroy + set destroyed + } 0 + do_test func3-1.2 { + sqlite3_create_function_v2 db f2 -1 utf8 -func f2 + set destroyed + } 0 + do_test func3-1.3 { + sqlite3_create_function_v2 db f2 -1 utf16le -func f2 + set destroyed + } 0 + do_test func3-1.4 { + sqlite3_create_function_v2 db f2 -1 utf16be -func f2 + set destroyed + } 1 +} do_test func3-2.1 { set destroyed 0 diff --git a/test/fuzz_malloc.test b/test/fuzz_malloc.test index f2209aab..1e31babd 100644 --- a/test/fuzz_malloc.test +++ b/test/fuzz_malloc.test @@ -47,7 +47,7 @@ proc do_fuzzy_malloc_test {testname args} { sqlite3_memdebug_fail -1 db close - file delete test.db test.db-journal + delete_file test.db test.db-journal sqlite3 db test.db set ::prep $::fuzzyopts(-sqlprep) execsql $::prep diff --git a/test/fuzzer1.test b/test/fuzzer1.test index d0575d2d..6c232118 100644 --- a/test/fuzzer1.test +++ b/test/fuzzer1.test @@ -1376,7 +1376,7 @@ do_test fuzzer1-2.3 { AND f2.distance<=200 AND streetname.n>=f2.word AND streetname.n<=(f2.word || x'F7BFBFBF') } -} {steelewood tallia tallu talwyn taymouth thelema trailer {tyler finley}} +} {{tyler finley} trailer taymouth steelewood tallia tallu talwyn thelema} finish_test diff --git a/test/hook.test b/test/hook.test index c4dfb2e4..a195275c 100644 --- a/test/hook.test +++ b/test/hook.test @@ -95,7 +95,7 @@ do_test hook-3.9 { # Ticket #3564. # do_test hook-3.10 { - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal sqlite3 db2 test2.db proc commit_hook {} { set y [db2 one {SELECT y FROM t3 WHERE y>10}] @@ -217,7 +217,7 @@ ifcapable trigger { set ::update_hook {} ifcapable attach { do_test hook-4.2.3 { - file delete -force test2.db + forcedelete test2.db execsql { ATTACH 'test2.db' AS aux; CREATE TABLE aux.t3(a INTEGER PRIMARY KEY, b); diff --git a/test/incrblob.test b/test/incrblob.test index 9c9389eb..388c4ba3 100644 --- a/test/incrblob.test +++ b/test/incrblob.test @@ -120,7 +120,7 @@ foreach AutoVacuumMode [list 0 1] { } db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db execsql "PRAGMA auto_vacuum = $AutoVacuumMode" @@ -379,7 +379,7 @@ ifcapable vtab { # ifcapable attach { do_test incrblob-5.1 { - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal set ::size [expr [file size [info script]]] execsql { ATTACH 'test2.db' AS aux; @@ -584,7 +584,7 @@ set ::data [read $fd 14000] close $fd db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db do_test incrblob-7.2.1 { diff --git a/test/incrblob_err.test b/test/incrblob_err.test index b4c25877..35d37fee 100644 --- a/test/incrblob_err.test +++ b/test/incrblob_err.test @@ -35,6 +35,7 @@ do_malloc_test 1 -tclprep { } } -tclbody { set ::blob [db incrblob blobs v 1] + fconfigure $::blob -translation binary set rc [catch {puts -nonewline $::blob $::data}] if {$rc} { error "out of memory" } } @@ -71,8 +72,7 @@ do_malloc_test 3 -tclprep { if {$rc} { error "out of memory" } -} - +} do_ioerr_test incrblob_err-4 -cksum 1 -sqlprep { CREATE TABLE blobs(k, v BLOB); @@ -87,6 +87,7 @@ do_ioerr_test incrblob_err-5 -cksum 1 -sqlprep { INSERT INTO blobs VALUES(1, zeroblob(length(CAST($::data AS BLOB)))); } -tclbody { set ::blob [db incrblob blobs v 1] + fconfigure $::blob -translation binary puts -nonewline $::blob $::data close $::blob } @@ -96,6 +97,7 @@ do_ioerr_test incrblob_err-6 -cksum 1 -sqlprep { INSERT INTO blobs VALUES(1, $::data || $::data || $::data); } -tclbody { set ::blob [db incrblob blobs v 1] + fconfigure $::blob -translation binary seek $::blob -20 end puts -nonewline $::blob "12345678900987654321" close $::blob diff --git a/test/incrvacuum.test b/test/incrvacuum.test index d037d8e7..91f5c8e1 100644 --- a/test/incrvacuum.test +++ b/test/incrvacuum.test @@ -331,7 +331,7 @@ proc compare_dbs {A B tname} { set ::str1 [string repeat abcdefghij 130] set ::str2 [string repeat 1234567890 105] -file delete -force test1.db test1.db-journal test2.db test2.db-journal +forcedelete test1.db test1.db-journal test2.db test2.db-journal sqlite3 db1 test1.db sqlite3 db2 test2.db execsql { PRAGMA auto_vacuum = 'none' } db1 @@ -475,7 +475,7 @@ do_test incrvacuum-8.1 { # do_test incrvacuum-9.1 { db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db execsql { @@ -593,7 +593,7 @@ do_test incrvacuum-10.8 { # vacuum mode. # db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db ifcapable default_autovacuum { @@ -651,7 +651,7 @@ do_test incrvacuum-11.7 { # auto_vacuum = XXX" statement is executed. # db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db do_test incrvacuum-12.1 { @@ -692,7 +692,7 @@ do_test incrvacuum-12.5 { # db2 close db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db ; set ::DB [sqlite3_connection_pointer db] sqlite3 db2 test.db @@ -743,7 +743,7 @@ if {[permutation] == ""} { do_test incrvacuum-15.1 { db close db2 close - file delete -force test.db + forcedelete test.db sqlite3 db test.db set str [string repeat "abcdefghij" 500] diff --git a/test/incrvacuum2.test b/test/incrvacuum2.test index 902517c9..e67a0862 100644 --- a/test/incrvacuum2.test +++ b/test/incrvacuum2.test @@ -70,7 +70,7 @@ do_test incrvacuum2-1.4 { # ifcapable attach { do_test incrvacuum2-2.1 { - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal execsql { ATTACH DATABASE 'test2.db' AS aux; PRAGMA aux.auto_vacuum=incremental; diff --git a/test/incrvacuum_ioerr.test b/test/incrvacuum_ioerr.test index 47027b82..946925d7 100644 --- a/test/incrvacuum_ioerr.test +++ b/test/incrvacuum_ioerr.test @@ -108,7 +108,7 @@ do_ioerr_test incrvacuum-ioerr-3 -start 1 -cksum 1 -tclprep { ifcapable shared_cache { catch { db close } - file delete -force test.db + forcedelete test.db set ::enable_shared_cache [sqlite3_enable_shared_cache 1] # Create two connections to a single shared-cache: diff --git a/test/index4.test b/test/index4.test new file mode 100644 index 00000000..018ed744 --- /dev/null +++ b/test/index4.test @@ -0,0 +1,126 @@ +# 2011 July 9 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the CREATE INDEX statement. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +set testprefix index4 + +do_execsql_test 1.1 { + BEGIN; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(102)); + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 2 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 4 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 8 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 16 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 32 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 64 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 128 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 256 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 512 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 1024 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 2048 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 4096 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 8192 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 16384 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 32768 + INSERT INTO t1 SELECT randomblob(102) FROM t1; -- 65536 + COMMIT; +} + +do_execsql_test 1.2 { + CREATE INDEX i1 ON t1(x); +} +do_execsql_test 1.3 { + PRAGMA integrity_check +} {ok} + +# The same test again - this time with limited memory. +# +ifcapable memorymanage { + set soft_limit [sqlite3_soft_heap_limit 50000] + + db close + sqlite3 db test.db + + do_execsql_test 1.4 { + PRAGMA cache_size = 10; + CREATE INDEX i2 ON t1(x); + } + do_execsql_test 1.5 { + PRAGMA integrity_check + } {ok} + + sqlite3_soft_heap_limit $soft_limit +} + + +do_execsql_test 1.6 { + BEGIN; + DROP TABLE t1; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('a'); + INSERT INTO t1 VALUES('b'); + INSERT INTO t1 VALUES('c'); + INSERT INTO t1 VALUES('d'); + INSERT INTO t1 VALUES('e'); + INSERT INTO t1 VALUES('f'); + INSERT INTO t1 VALUES('g'); + INSERT INTO t1 VALUES(NULL); + INSERT INTO t1 SELECT randomblob(1202) FROM t1; -- 16 + INSERT INTO t1 SELECT randomblob(2202) FROM t1; -- 32 + INSERT INTO t1 SELECT randomblob(3202) FROM t1; -- 64 + INSERT INTO t1 SELECT randomblob(4202) FROM t1; -- 128 + INSERT INTO t1 SELECT randomblob(5202) FROM t1; -- 256 + COMMIT; + CREATE INDEX i1 ON t1(x); + PRAGMA integrity_check +} {ok} + +do_execsql_test 1.7 { + BEGIN; + DROP TABLE t1; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('a'); + COMMIT; + CREATE INDEX i1 ON t1(x); + PRAGMA integrity_check +} {ok} + +do_execsql_test 1.8 { + BEGIN; + DROP TABLE t1; + CREATE TABLE t1(x); + COMMIT; + CREATE INDEX i1 ON t1(x); + PRAGMA integrity_check +} {ok} + +do_execsql_test 2.1 { + BEGIN; + CREATE TABLE t2(x); + INSERT INTO t2 VALUES(14); + INSERT INTO t2 VALUES(35); + INSERT INTO t2 VALUES(15); + INSERT INTO t2 VALUES(35); + INSERT INTO t2 VALUES(16); + COMMIT; +} +do_catchsql_test 2.2 { + CREATE UNIQUE INDEX i3 ON t2(x); +} {1 {indexed columns are not unique}} + + +finish_test diff --git a/test/indexfault.test b/test/indexfault.test new file mode 100644 index 00000000..efe49321 --- /dev/null +++ b/test/indexfault.test @@ -0,0 +1,342 @@ +# 2011 August 08 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +source $testdir/malloc_common.tcl + +ifcapable !mergesort { + finish_test + return +} + +set testprefix indexfault + +# Set up the custom fault-injector. This is further configured by using +# different values for $::custom_filter and different implementations +# of Tcl proc [xCustom] for each test case. +# +proc install_custom_faultsim {} { + set ::FAULTSIM(custom) [list \ + -injectinstall custom_injectinstall \ + -injectstart custom_injectstart \ + -injectstop custom_injectstop \ + -injecterrlist {{1 {disk I/O error}}} \ + -injectuninstall custom_injectuninstall \ + ] + proc custom_injectinstall {} { + testvfs shmfault -default true + shmfault filter $::custom_filter + shmfault script xCustom + } + proc custom_injectuninstall {} { + catch {db close} + catch {db2 close} + shmfault delete + } + set ::custom_ifail -1 + set ::custom_nfail -1 + proc custom_injectstart {iFail} { + set ::custom_ifail $iFail + set ::custom_nfail 0 + } + proc custom_injectstop {} { + set ::custom_ifail -1 + return $::custom_nfail + } +} +proc uninstall_custom_faultsim {} { + unset -nocomplain ::FAULTSIM(custom) +} + + +#------------------------------------------------------------------------- +# These tests - indexfault-1.* - Build an index on a smallish table with +# all different kinds of fault-injection. The CREATE INDEX is run once +# with default options and once with a 50KB soft-heap-limit. +# +do_execsql_test 1.0 { + BEGIN; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(202)); + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 2 + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 4 + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 8 + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 16 + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 32 + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 64 + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 128 + INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 256 + COMMIT; +} +faultsim_save_and_close + +do_faultsim_test 1.1 -prep { + faultsim_restore_and_reopen +} -body { + execsql { CREATE INDEX i1 ON t1(x) } + faultsim_test_result {0 {}} + faultsim_integrity_check +} +ifcapable memorymanage { + set soft_limit [sqlite3_soft_heap_limit 50000] + do_faultsim_test 2.1 -prep { + faultsim_restore_and_reopen + } -body { + execsql { CREATE INDEX i1 ON t1(x) } + faultsim_test_result {0 {}} + } + sqlite3_soft_heap_limit $soft_limit +} + +#------------------------------------------------------------------------- +# These are similar to the indexfault-1.* tests, except they create an +# index with more than one column. +# +sqlite3 db test.db +do_execsql_test 2.0 { + BEGIN; + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(t,u,v,w,x,y,z); + INSERT INTO t1 VALUES( + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) + ); + INSERT INTO t1 SELECT + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 2 + INSERT INTO t1 SELECT + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 4 + INSERT INTO t1 SELECT + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 8 + INSERT INTO t1 SELECT + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 16 + INSERT INTO t1 SELECT + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 32 + INSERT INTO t1 SELECT + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 64 + INSERT INTO t1 SELECT + randomblob(30), randomblob(30), randomblob(30), randomblob(30), + randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 128 + COMMIT; +} +faultsim_save_and_close + +do_faultsim_test 2.1 -prep { + faultsim_restore_and_reopen +} -body { + execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) } + faultsim_test_result {0 {}} + faultsim_integrity_check +} +ifcapable memorymanage { + set soft_limit [sqlite3_soft_heap_limit 50000] + do_faultsim_test 2.2 -prep { + faultsim_restore_and_reopen + } -body { + execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) } + faultsim_test_result {0 {}} + } + sqlite3_soft_heap_limit $soft_limit +} + +#------------------------------------------------------------------------- +# The following tests - indexfault-2.* - all attempt to build a index +# on table t1 in the main database with injected IO errors. Individual +# test cases work as follows: +# +# 3.1: IO errors injected into xOpen() calls. +# 3.2: As 7.1, but with a low (50KB) soft-heap-limit. +# +# 3.3: IO errors injected into the first 200 write() calls made on the +# second temporary file. +# 3.4: As 7.3, but with a low (50KB) soft-heap-limit. +# +# 3.5: After a certain amount of data has been read from the main database +# file (and written into the temporary b-tree), sqlite3_release_memory() +# is called to free as much memory as possible. This causes the temp +# b-tree to be flushed to disk. So that before its contents can be +# transfered to a PMA they must be read back from disk - creating extra +# opportunities for IO errors. +# +install_custom_faultsim + +# Set up a table to build indexes on. Save the setup using the +# [faultsim_save_and_close] mechanism. +# +sqlite3 db test.db +do_execsql_test 3.0 { + BEGIN; + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(11000)); + INSERT INTO t1 SELECT randomblob(11001) FROM t1; -- 2 + INSERT INTO t1 SELECT randomblob(11002) FROM t1; -- 4 + INSERT INTO t1 SELECT randomblob(11003) FROM t1; -- 8 + INSERT INTO t1 SELECT randomblob(11004) FROM t1; -- 16 + INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 32 + INSERT INTO t1 SELECT randomblob(11006) FROM t1; -- 64 + INSERT INTO t1 SELECT randomblob(11007) FROM t1; -- 128 + INSERT INTO t1 SELECT randomblob(11008) FROM t1; -- 256 + INSERT INTO t1 SELECT randomblob(11009) FROM t1; -- 512 + COMMIT; +} +faultsim_save_and_close + +set ::custom_filter xOpen +proc xCustom {args} { + incr ::custom_ifail -1 + if {$::custom_ifail==0} { + incr ::custom_nfail + return "SQLITE_IOERR" + } + return "SQLITE_OK" +} +do_faultsim_test 3.1 -faults custom -prep { + faultsim_restore_and_reopen +} -body { + execsql { CREATE INDEX i1 ON t1(x) } + faultsim_test_result {0 {}} +} +ifcapable memorymanage { + set soft_limit [sqlite3_soft_heap_limit 50000] + do_faultsim_test 3.2 -faults custom -prep { + faultsim_restore_and_reopen + } -body { + execsql { CREATE INDEX i1 ON t1(x) } + faultsim_test_result {0 {}} + } + sqlite3_soft_heap_limit $soft_limit +} + +set ::custom_filter {xOpen xWrite} +proc xCustom {method args} { + if {$method == "xOpen"} { + if {[lindex $args 0] == ""} { + incr ::nTmpOpen 1 + if {$::nTmpOpen == 3} { return "failme" } + } + return "SQLITE_OK" + } + if {$::custom_ifail<200 && [lindex $args 1] == "failme"} { + incr ::custom_ifail -1 + if {$::custom_ifail==0} { + incr ::custom_nfail + return "SQLITE_IOERR" + } + } + return "SQLITE_OK" +} + +do_faultsim_test 3.3 -faults custom -prep { + faultsim_restore_and_reopen + set ::nTmpOpen 0 +} -body { + execsql { CREATE INDEX i1 ON t1(x) } + faultsim_test_result {0 {}} +} + +ifcapable memorymanage { + set soft_limit [sqlite3_soft_heap_limit 50000] + do_faultsim_test 3.4 -faults custom -prep { + faultsim_restore_and_reopen + set ::nTmpOpen 0 + } -body { + execsql { CREATE INDEX i1 ON t1(x) } + faultsim_test_result {0 {}} + } + sqlite3_soft_heap_limit $soft_limit +} + +uninstall_custom_faultsim + +#------------------------------------------------------------------------- +# Test 4: After a certain amount of data has been read from the main database +# file (and written into the temporary b-tree), sqlite3_release_memory() is +# called to free as much memory as possible. This causes the temp b-tree to be +# flushed to disk. So that before its contents can be transfered to a PMA they +# must be read back from disk - creating extra opportunities for IO errors. +# +install_custom_faultsim + +catch { db close } +forcedelete test.db +sqlite3 db test.db + +do_execsql_test 4.0 { + BEGIN; + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(11000)); + INSERT INTO t1 SELECT randomblob(11001) FROM t1; -- 2 + INSERT INTO t1 SELECT randomblob(11002) FROM t1; -- 4 + INSERT INTO t1 SELECT randomblob(11003) FROM t1; -- 8 + INSERT INTO t1 SELECT randomblob(11004) FROM t1; -- 16 + INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 32 + INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 64 + COMMIT; +} +faultsim_save_and_close + +testvfs tvfs +tvfs script xRead +tvfs filter xRead +set ::nRead 0 +proc xRead {method file args} { + if {[file tail $file] == "test.db"} { incr ::nRead } +} + +do_test 4.1 { + sqlite3 db test.db -vfs tvfs + execsql { CREATE INDEX i1 ON t1(x) } +} {} + +db close +tvfs delete + +set ::custom_filter xRead +proc xCustom {method file args} { + incr ::nReadCall + if {$::nReadCall >= ($::nRead/5)} { + if {$::nReadCall == ($::nRead/5)} { + set nByte [sqlite3_release_memory [expr 64*1024*1024]] + sqlite3_soft_heap_limit 20000 + } + if {$file == ""} { + incr ::custom_ifail -1 + if {$::custom_ifail==0} { + incr ::custom_nfail + return "SQLITE_IOERR" + } + } + } + return "SQLITE_OK" +} + +do_faultsim_test 4.2 -faults custom -prep { + faultsim_restore_and_reopen + set ::nReadCall 0 + sqlite3_soft_heap_limit 0 +} -body { + execsql { CREATE INDEX i1 ON t1(x) } + faultsim_test_result {0 {}} +} + +uninstall_custom_faultsim + +finish_test diff --git a/test/insert4.test b/test/insert4.test index 44b428a1..cb02b9dc 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -112,7 +112,7 @@ do_test insert4-2.4.1 { INSERT INTO t3 SELECT DISTINCT * FROM t2; SELECT * FROM t3; } -} {1 9 9 1} +} {9 1 1 9} xferopt_test insert4-2.4.2 0 do_test insert4-2.4.3 { catchsql { diff --git a/test/insert5.test b/test/insert5.test index e48c2c32..1e58902e 100644 --- a/test/insert5.test +++ b/test/insert5.test @@ -34,7 +34,7 @@ proc uses_temp_table {sql} { # Construct the sample database. # do_test insert5-1.0 { - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal execsql { CREATE TABLE MAIN(Id INTEGER, Id1 INTEGER); CREATE TABLE B(Id INTEGER, Id1 INTEGER); diff --git a/test/io.test b/test/io.test index 0cc26eff..58caeeeb 100644 --- a/test/io.test +++ b/test/io.test @@ -225,7 +225,7 @@ do_test io-2.6.2 { } } {1 {unable to open database file}} do_test io-2.6.3 { - file delete -force test.db-journal + forcedelete test.db-journal catchsql { COMMIT } } {0 {}} do_test io-2.6.4 { @@ -237,7 +237,7 @@ do_test io-2.6.4 { # is created during execution of the COMMIT statement, so we have to # use the same technique to check that it is created as in the above # block. -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal ifcapable attach { do_test io-2.7.1 { execsql { @@ -261,7 +261,7 @@ ifcapable attach { catchsql { COMMIT } } {1 {unable to open database file}} do_test io-2.7.5 { - file delete -force test2.db-journal + forcedelete test2.db-journal catchsql { COMMIT } } {1 {cannot commit - no transaction is active}} do_test io-2.7.6 { @@ -304,7 +304,7 @@ do_test io-2.9.1 { do_test io-2.9.2 { execsql { ROLLBACK; } db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db -vfs devsym execsql { PRAGMA auto_vacuum = OFF; @@ -375,7 +375,7 @@ sqlite3_simulate_device -char sequential -sectorsize 0 ifcapable pager_pragmas { do_test io-3.1 { db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db -vfs devsym db eval { PRAGMA auto_vacuum=OFF; @@ -544,7 +544,7 @@ foreach {char sectorsize pgsize} { incr tn if {$pgsize>$::SQLITE_MAX_PAGE_SIZE} continue db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3_simulate_device -char $char -sectorsize $sectorsize sqlite3 db test.db -vfs devsym db eval { diff --git a/test/ioerr.test b/test/ioerr.test index f9b95555..b237439e 100644 --- a/test/ioerr.test +++ b/test/ioerr.test @@ -183,8 +183,8 @@ if {$tcl_platform(platform)!="windows"} { BEGIN; INSERT INTO t1 VALUES(3, 4); } - copy_file test2.db test.db - copy_file test2.db-journal test.db-journal + forcecopy test2.db test.db + forcecopy test2.db-journal test.db-journal db2 close } -tclbody { sqlite3 db test.db @@ -219,11 +219,11 @@ if {$tcl_platform(platform)=="unix"} { BEGIN; INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2); } - copy_file test.db-journal test2.db-journal + forcecopy test.db-journal test2.db-journal execsql { COMMIT; } - copy_file test2.db-journal test.db-journal + forcecopy test2.db-journal test.db-journal set f [open test.db-journal a] fconfigure $f -encoding binary puts -nonewline $f "hello" diff --git a/test/ioerr4.test b/test/ioerr4.test index 3a74a88a..defa3268 100644 --- a/test/ioerr4.test +++ b/test/ioerr4.test @@ -31,7 +31,7 @@ do_test ioerr4-1.1 { set ::enable_shared_cache [sqlite3_enable_shared_cache 1] } {0} do_test ioerr4-1.2 { - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db sqlite3 db2 test.db db eval { @@ -79,12 +79,12 @@ do_test ioerr4-1.6 { # db close db2 close -file copy -force test.db test.db-bu +forcecopy test.db test.db-bu do_ioerr_test ioerr4-2 -tclprep { catch {db2 close} db close - file delete -force test.db test.db-journal - file copy -force test.db-bu test.db + forcedelete test.db test.db-journal + forcecopy test.db-bu test.db sqlite3_enable_shared_cache 1 set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db] db eval {PRAGMA auto_vacuum=INCREMENTAL} @@ -94,7 +94,7 @@ do_ioerr_test ioerr4-2 -tclprep { } db2 close -file delete -force test.db-bu +forcedelete test.db-bu sqlite3_enable_shared_cache $::enable_shared_cache finish_test diff --git a/test/journal1.test b/test/journal1.test index a1b17b41..2fdadfd6 100644 --- a/test/journal1.test +++ b/test/journal1.test @@ -20,7 +20,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl # These tests will not work on windows because windows uses -# manditory file locking which breaks the file copy command. +# manditory file locking which breaks the copy_file command. # if {$tcl_platform(platform)=="windows"} { finish_test @@ -51,13 +51,13 @@ do_test journal1-1.2 { BEGIN; DELETE FROM t1; } - file copy -force test.db-journal test.db-journal-bu + forcecopy test.db-journal test.db-journal-bu execsql { ROLLBACK; } db close - file delete test.db - file copy test.db-journal-bu test.db-journal + delete_file test.db + copy_file test.db-journal-bu test.db-journal sqlite3 db test.db catchsql { SELECT * FROM sqlite_master diff --git a/test/journal2.test b/test/journal2.test index 2b5d8fa8..25ce9416 100644 --- a/test/journal2.test +++ b/test/journal2.test @@ -167,7 +167,7 @@ do_test journal2-1.13 { } {1 {disk I/O error}} db2 close unset ::tvfs_error_on_write -file copy -force test.db testX.db +forcecopy test.db testX.db do_test journal2-1.14 { file exists test.db-journal } 1 do_test journal2-1.15 { diff --git a/test/journal3.test b/test/journal3.test index 7d297222..f1bf89f8 100644 --- a/test/journal3.test +++ b/test/journal3.test @@ -35,7 +35,7 @@ if {$::tcl_platform(platform) == "unix"} { db close set effective [format %.5o [expr $permissions & ~$umask]] do_test journal3-1.2.$tn.1 { - catch { file delete -force test.db-journal } + catch { forcedelete test.db-journal } file attributes test.db -permissions $permissions file attributes test.db -permissions } $permissions diff --git a/test/jrnlmode.test b/test/jrnlmode.test index eab74d65..b1007c49 100644 --- a/test/jrnlmode.test +++ b/test/jrnlmode.test @@ -200,7 +200,7 @@ ifcapable attach { } ifcapable attach { - file delete -force test2.db + forcedelete test2.db do_test jrnlmode-2.1 { execsql { ATTACH 'test2.db' AS aux; @@ -242,8 +242,8 @@ ifcapable attach { # Test caes jrnlmode-3.X verify that ticket #3127 has been fixed. # db close - file delete -force test2.db - file delete -force test.db + forcedelete test2.db + forcedelete test.db sqlite3 db test.db do_test jrnlmode-3.1 { @@ -270,7 +270,7 @@ ifcapable attach { ifcapable autovacuum&&pragma { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db do_test jrnlmode-4.1 { execsql { @@ -303,7 +303,7 @@ ifcapable autovacuum&&pragma { # pragma. ifcapable pragma { db close - file delete -force test.db test2.db test3.db + forcedelete test.db test2.db test3.db sqlite3 db test.db do_test jrnlmode-5.1 { @@ -511,7 +511,7 @@ ifcapable pragma { ifcapable pragma { catch { db close } do_test jrnlmode-7.1 { - foreach f [glob -nocomplain test.db*] { file delete -force $f } + foreach f [glob -nocomplain test.db*] { forcedelete $f } sqlite3 db test.db execsql { PRAGMA journal_mode = memory; diff --git a/test/jrnlmode2.test b/test/jrnlmode2.test index dc3bc270..6ea87d70 100644 --- a/test/jrnlmode2.test +++ b/test/jrnlmode2.test @@ -112,7 +112,7 @@ do_test jrnlmode2-2.4 { do_test jrnlmode2-2.5 { db close - file delete test.db-journal + delete_file test.db-journal } {} do_test jrnlmode2-2.6 { sqlite3 db2 test.db -readonly 1 diff --git a/test/jrnlmode3.test b/test/jrnlmode3.test index 6ae1346e..43da6579 100644 --- a/test/jrnlmode3.test +++ b/test/jrnlmode3.test @@ -48,7 +48,7 @@ do_test jrnlmode3-1.2 { } {1} db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db do_test jrnlmode3-2.1 { @@ -85,7 +85,7 @@ foreach fromjmode $all_journal_modes { # Start with a fresh database connection an empty database file. # db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db # Initialize the journal mode. diff --git a/test/like.test b/test/like.test index bd9a6c39..767efd58 100644 --- a/test/like.test +++ b/test/like.test @@ -70,12 +70,15 @@ do_test like-1.4 { } } {ABC abc} do_test like-1.5.1 { + # Use sqlite3_exec() to verify fix for ticket [25ee81271091] 2011-06-26 + sqlite3_exec db {PRAGMA case_sensitive_like=on} +} {0 {}} +do_test like-1.5.2 { execsql { - PRAGMA case_sensitive_like=on; SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1; } } {abc} -do_test like-1.5.2 { +do_test like-1.5.3 { execsql { PRAGMA case_sensitive_like; -- no argument; does not change setting SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1; @@ -305,8 +308,8 @@ do_test like-3.18 { # do_test like-3.19 { set sqlite_like_count 0 + db eval {CREATE INDEX i1 ON t1(x);} queryplan { - CREATE INDEX i1 ON t1(x); SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1; } } {abc abcd nosort {} i1} @@ -519,7 +522,7 @@ do_test like-5.24 { } } {zz-lower-lower zZ-lower-upper Zz-upper-lower ZZ-upper-upper nosort {} i2} do_test like-5.25 { - queryplan { + db eval { PRAGMA case_sensitive_like=on; CREATE TABLE t3(x TEXT); CREATE INDEX i3 ON t3(x); @@ -527,6 +530,8 @@ do_test like-5.25 { INSERT INTO t3 VALUES('zZ-lower-upper'); INSERT INTO t3 VALUES('Zz-upper-lower'); INSERT INTO t3 VALUES('zz-lower-lower'); + } + queryplan { SELECT x FROM t3 WHERE x LIKE 'zz%'; } } {zz-lower-lower nosort {} i3} diff --git a/test/loadext.test b/test/loadext.test index db5745b4..8f8339ec 100644 --- a/test/loadext.test +++ b/test/loadext.test @@ -134,7 +134,7 @@ sqlite3_enable_load_extension db 1 # Try to load an extension for which the file does not exist. # do_test loadext-2.1 { - file delete -force ${testextension}xx + forcedelete ${testextension}xx set rc [catch { sqlite3_load_extension db "${testextension}xx" } msg] diff --git a/test/lock4.test b/test/lock4.test index 06ee88df..b0b1c74f 100644 --- a/test/lock4.test +++ b/test/lock4.test @@ -26,7 +26,7 @@ do_test lock4-1.1 { PRAGMA auto_vacuum=OFF; CREATE TABLE t1(x); } - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal sqlite3 db2 test2.db db2 eval { PRAGMA auto_vacuum=OFF; diff --git a/test/lock5.test b/test/lock5.test index 6ec86ba7..f0d49550 100644 --- a/test/lock5.test +++ b/test/lock5.test @@ -24,7 +24,7 @@ if {[catch {sqlite3 db test.db -vfs unix-none} msg]} { return } db close -file delete -force test.db.lock +forcedelete test.db.lock ifcapable lock_proxy_pragmas { set ::using_proxy 0 @@ -100,7 +100,7 @@ do_test lock5-dotfile.X { ##################################################################### -file delete -force test.db +forcedelete test.db if {[catch {sqlite3 db test.db -vfs unix-flock} msg]} { finish_test return diff --git a/test/main.test b/test/main.test index dbf90410..5bbc52b8 100644 --- a/test/main.test +++ b/test/main.test @@ -301,7 +301,7 @@ ifcapable {trigger} { if {[permutation] == ""} { do_test main-2.0 { catch {db close} - file delete -force test.db + forcedelete test.db set fd [open test.db w] puts $fd hi! close $fd @@ -314,16 +314,16 @@ if {[permutation] == ""} { # do_test main-3.1 { catch {db close} - foreach f [glob -nocomplain testdb/*] {file delete -force $f} - file delete -force testdb + foreach f [glob -nocomplain testdb/*] {forcedelete $f} + forcedelete testdb sqlite3 db testdb set v [catch {execsql {SELECT * from T1 where x!!5}} msg] lappend v $msg } {1 {unrecognized token: "!!"}} do_test main-3.2 { catch {db close} - foreach f [glob -nocomplain testdb/*] {file delete -force $f} - file delete -force testdb + foreach f [glob -nocomplain testdb/*] {forcedelete $f} + forcedelete testdb sqlite3 db testdb set v [catch {execsql {SELECT * from T1 where ^x}} msg] lappend v $msg @@ -442,8 +442,8 @@ do_test main-3.2.30 { do_test main-3.3 { catch {db close} - foreach f [glob -nocomplain testdb/*] {file delete -force $f} - file delete -force testdb + foreach f [glob -nocomplain testdb/*] {forcedelete $f} + forcedelete testdb sqlite3 db testdb execsql { create table T1(X REAL); /* C-style comments allowed */ diff --git a/test/malloc.test b/test/malloc.test index 9bd5314b..0d213d7b 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -270,7 +270,7 @@ do_malloc_test 9 -sqlprep { do_malloc_test 10 -tclprep { catch {db2 close} db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db sqlite3_extended_result_codes db 1 db eval {CREATE TABLE abc(a, b, c)} @@ -341,8 +341,8 @@ if {$tcl_platform(platform)!="windows"} { BEGIN; INSERT INTO t1 VALUES(3, 4); } - copy_file test2.db test.db - copy_file test2.db-journal test.db-journal + forcecopy test2.db test.db + forcecopy test2.db-journal test.db-journal db2 close } -tclbody { sqlite3 db test.db @@ -499,7 +499,7 @@ unset static_string ifcapable attach { do_malloc_test 20 -tclprep { db close - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal sqlite3 db test2.db sqlite3_extended_result_codes db 1 db eval {CREATE TABLE t1(x);} @@ -867,32 +867,6 @@ if {[db eval {PRAGMA locking_mode}]!="exclusive"} { catch { db2 close } } -ifcapable stat2&&utf16 { - do_malloc_test 38 -tclprep { - add_test_collate db 0 0 1 - execsql { - ANALYZE; - CREATE TABLE t4(x COLLATE test_collate); - CREATE INDEX t4x ON t4(x); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 0, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 1, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 2, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 3, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 4, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 5, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 6, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 7, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 8, 'aaa'); - INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 9, 'aaa'); - } - db close - sqlite3 db test.db - sqlite3_db_config_lookaside db 0 0 0 - add_test_collate db 0 0 1 - } -sqlbody { - SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc' - } -} # Test that if an OOM error occurs, aux-data is still correctly destroyed. # This test case was causing either a memory-leak or an assert() failure diff --git a/test/malloc3.test b/test/malloc3.test index 73d2d396..2dfde466 100644 --- a/test/malloc3.test +++ b/test/malloc3.test @@ -463,7 +463,7 @@ TEST 29 { # Test a simple multi-file transaction # -file delete -force test2.db +forcedelete test2.db ifcapable attach { SQL {ATTACH 'test2.db' AS aux;} SQL {BEGIN} @@ -650,7 +650,7 @@ run_test $::run_test_script 1 # Close and reopen the db. db close -file delete -force test.db test.db-journal test2.db test2.db-journal +forcedelete test.db test.db-journal test2.db test2.db-journal sqlite3 db test.db sqlite3_extended_result_codes db 1 set ::DB [sqlite3_connection_pointer db] diff --git a/test/malloc5.test b/test/malloc5.test index 73885b22..71f56bbb 100644 --- a/test/malloc5.test +++ b/test/malloc5.test @@ -219,7 +219,7 @@ do_test malloc5-4.2 { execsql {SELECT * FROM abc} set nMaxBytes [sqlite3_memory_highwater 1] puts -nonewline " (Highwater mark: $nMaxBytes) " - expr $nMaxBytes <= 100000 + expr $nMaxBytes <= 110000 } {1} do_test malloc5-4.3 { # Check that the content of table abc is at least roughly as expected. @@ -275,7 +275,7 @@ proc nPage {db} { set stats(page) } db close -file delete -force test.db test.db-journal test2.db test2.db-journal +forcedelete test.db test.db-journal test2.db test2.db-journal # This block of test-cases (malloc5-6.1.*) prepares two database files # for the subsequent tests. @@ -304,7 +304,7 @@ do_test malloc5-6.1.1 { SELECT randstr(50,50), randstr(75,75), randstr(100,100) FROM abc; COMMIT; } - copy_file test.db test2.db + forcecopy test.db test2.db sqlite3 db2 test2.db list \ [expr ([file size test.db]/1024)>20] [expr ([file size test2.db]/1024)>20] diff --git a/test/mallocA.test b/test/mallocA.test index 08f69302..89951276 100644 --- a/test/mallocA.test +++ b/test/mallocA.test @@ -27,7 +27,7 @@ if {!$MEMDEBUG} { # Construct a test database # -file delete -force test.db.bu +forcedelete test.db.bu db eval { CREATE TABLE t1(a COLLATE NOCASE,b,c); INSERT INTO t1 VALUES(1,2,3); @@ -38,7 +38,7 @@ db eval { CREATE TABLE t2(x,y,z); } db close -file copy test.db test.db.bu +copy_file test.db test.db.bu do_malloc_test mallocA-1 -testdb test.db.bu -sqlbody { @@ -74,5 +74,5 @@ do_test malloc-99.X { set sqlite_open_file_count } {0} -file delete -force test.db.bu +forcedelete test.db.bu finish_test diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index e7f61564..5937b958 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -408,7 +408,7 @@ proc do_malloc_test {tn args} { set zRepeat "transient" if {$::iRepeat} {set zRepeat "persistent"} restore_prng_state - foreach file [glob -nocomplain test.db-mj*] {file delete -force $file} + foreach file [glob -nocomplain test.db-mj*] {forcedelete $file} do_test ${tn}.${zRepeat}.${::n} { @@ -425,7 +425,7 @@ proc do_malloc_test {tn args} { forcedelete test2.db-journal forcedelete test2.db-wal if {[info exists ::mallocopts(-testdb)]} { - file copy $::mallocopts(-testdb) test.db + copy_file $::mallocopts(-testdb) test.db } catch { sqlite3 db test.db } if {[info commands db] ne ""} { diff --git a/test/manydb.test b/test/manydb.test index b9a8eaf8..974a5b8e 100644 --- a/test/manydb.test +++ b/test/manydb.test @@ -44,7 +44,7 @@ foreach fd $filehandles { close $fd } catch { - file delete -force testfile.1 + forcedelete testfile.1 } set N [expr $i / $num_fd_per_openwrite_db] @@ -92,7 +92,7 @@ for {set i 0} {$i<$N} {incr i} { for {set i 0} {$i<$N} {incr i} { do_test manydb-3.$i { db$i close - file delete -force $dbname($i) + forcedelete $dbname($i) } {} } diff --git a/test/memsubsys1.test b/test/memsubsys1.test index 3bb2cc71..7eecf083 100644 --- a/test/memsubsys1.test +++ b/test/memsubsys1.test @@ -32,7 +32,7 @@ if {[permutation] == "memsubsys1"} { # proc build_test_db {testname pragmas} { catch {db close} - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 db eval $pragmas diff --git a/test/memsubsys2.test b/test/memsubsys2.test index ec554775..a40f4e4f 100644 --- a/test/memsubsys2.test +++ b/test/memsubsys2.test @@ -24,7 +24,7 @@ sqlite3_reset_auto_extension # proc build_test_db {testname pragmas} { catch {db close} - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db db eval $pragmas db eval { diff --git a/test/misc1.test b/test/misc1.test index a78e4884..e3f1b955 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -491,7 +491,7 @@ do_test misc1-14.2b { } {1} do_test misc1-14.3 { cd .. - file delete -force tempdir + forcedelete tempdir execsql {COMMIT} file exists ./test.db-journal } {0} diff --git a/test/misc2.test b/test/misc2.test index f6fc3833..bb544c5f 100644 --- a/test/misc2.test +++ b/test/misc2.test @@ -165,7 +165,7 @@ do_test misc2-6.1 { ifcapable tclvar { do_test misc2-7.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { CREATE TABLE t1(x); @@ -265,7 +265,7 @@ ifcapable tclvar { # do_test misc2-7.11 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { CREATE TABLE t1(x); @@ -361,7 +361,7 @@ ifcapable tclvar { } db close -file delete -force test.db +forcedelete test.db sqlite3 db test.db catchsql { pragma recursive_triggers = off } diff --git a/test/misc3.test b/test/misc3.test index 94a43c43..81a8266b 100644 --- a/test/misc3.test +++ b/test/misc3.test @@ -270,7 +270,11 @@ ifcapable {explain} { CREATE UNIQUE INDEX ex1i1 ON ex1(a); EXPLAIN REINDEX; }] - regexp { IsUnique \d+ \d+ \d+ \d+ } $x + ifcapable mergesort { + regexp { SorterCompare \d+ \d+ \d+ } $x + } else { + regexp { IsUnique \d+ \d+ \d+ \d+ } $x + } } {1} if {[regexp {16} [db one {PRAGMA encoding}]]} { do_test misc3-6.11-utf16 { diff --git a/test/misc5.test b/test/misc5.test index 34b2284b..14ba44ea 100644 --- a/test/misc5.test +++ b/test/misc5.test @@ -505,7 +505,7 @@ ifcapable subquery { ) ORDER BY LOWER(artist) ASC; } - } {one} + } {two} } # Ticket #1370. Do not overwrite small files (less than 1024 bytes) @@ -514,7 +514,7 @@ ifcapable subquery { if {[permutation] == ""} { do_test misc5-4.1 { db close - file delete -force test.db + forcedelete test.db set fd [open test.db w] puts $fd "This is not really a database" close $fd @@ -544,7 +544,7 @@ do_test misc5-5.4 { # a UNION ALL query causes an error, not a crash. # db close -file delete -force test.db +forcedelete test.db sqlite3 db test.db ifcapable subquery&&compound { do_test misc5-6.1 { diff --git a/test/misc7.test b/test/misc7.test index 7d2ba6e8..9dee3278 100644 --- a/test/misc7.test +++ b/test/misc7.test @@ -30,7 +30,7 @@ do_test misc7-3 { # Try to open a directory: # do_test misc7-4 { - file delete mydir + delete_file mydir file mkdir mydir set rc [catch { sqlite3 db2 ./mydir @@ -41,7 +41,7 @@ do_test misc7-4 { # Try to open a file with a directory where its journal file should be. # do_test misc7-5 { - file delete mydir + delete_file mydir file mkdir mydir-journal sqlite3 db2 ./mydir catchsql { @@ -152,8 +152,8 @@ db2 close # after the omit_readlock pragma has been exercised. # do_test misc7-7.1 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { PRAGMA omit_readlock = 1; ATTACH 'test2.db' AS aux; @@ -254,8 +254,8 @@ ifcapable vtab { } db close -file delete -force test.db -file delete -force test.db-journal +forcedelete test.db +forcedelete test.db-journal sqlite3 db test.db ifcapable explain { @@ -278,8 +278,8 @@ ifcapable explain { } db close -file delete -force test.db -file delete -force test.db-journal +forcedelete test.db +forcedelete test.db-journal sqlite3 db test.db #-------------------------------------------------------------------- @@ -323,8 +323,8 @@ do_test misc7-15.2 { } {} db close -file delete -force test.db -file delete -force test.db-journal +forcedelete test.db +forcedelete test.db-journal sqlite3 db test.db do_ioerr_test misc7-16 -sqlprep { @@ -385,15 +385,15 @@ if {$tcl_platform(platform)!="windows" && $tcl_platform(platform)!="os2"} { BEGIN; DELETE FROM t3 WHERE (oid%3)==0; } - copy_file test.db bak.db - copy_file test.db-journal bak.db-journal + forcecopy test.db bak.db + forcecopy test.db-journal bak.db-journal execsql { COMMIT; } db close - copy_file bak.db test.db - copy_file bak.db-journal test.db-journal + forcecopy bak.db test.db + forcecopy bak.db-journal test.db-journal sqlite3 db test.db catch {file attributes test.db-journal -permissions r--------} @@ -484,6 +484,6 @@ do_test misc7-21.1 { db close -file delete -force test.db +forcedelete test.db finish_test diff --git a/test/misuse.test b/test/misuse.test index 3734aa01..71ee0118 100644 --- a/test/misuse.test +++ b/test/misuse.test @@ -39,8 +39,8 @@ proc catchsql2 {sql} { # do_test misuse-1.1 { db close - catch {file delete -force test2.db} - catch {file delete -force test2.db-journal} + catch {forcedelete test2.db} + catch {forcedelete test2.db-journal} sqlite3 db test2.db; set ::DB [sqlite3_connection_pointer db] execsql { CREATE TABLE t1(a,b); diff --git a/test/multiplex.test b/test/multiplex.test index 9278e842..3abdcf45 100644 --- a/test/multiplex.test +++ b/test/multiplex.test @@ -49,6 +49,7 @@ proc multiplex_set {db name chunk_size max_chunks} { # and files with the chunk extension. proc multiplex_delete {name} { global g_max_chunks + forcedelete $name for {set i 0} {$i<$g_max_chunks} {incr i} { forcedelete [multiplex_name $name $i] forcedelete [multiplex_name $name-journal $i] @@ -78,10 +79,9 @@ do_test multiplex-1.8 { sqlite3_multiplex_shutdown } {SQLITE_OK} do_test multiplex-1.9.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK} do_test multiplex-1.9.2 { sqlite3 db test.db } {} do_test multiplex-1.9.3 { multiplex_set db main 32768 16 } {SQLITE_OK} -do_test multiplex-1.9.4 { multiplex_set db main 32768 -1 } {SQLITE_MISUSE} -do_test multiplex-1.9.5 { multiplex_set db main -1 16 } {SQLITE_MISUSE} +do_test multiplex-1.9.4 { multiplex_set db main 32768 -1 } {SQLITE_OK} do_test multiplex-1.9.6 { multiplex_set db main 31 16 } {SQLITE_OK} -do_test multiplex-1.9.7 { multiplex_set db main 32768 100 } {SQLITE_MISUSE} +do_test multiplex-1.9.7 { multiplex_set db main 32768 100 } {SQLITE_OK} do_test multiplex-1.9.8 { multiplex_set db main 1073741824 1 } {SQLITE_OK} do_test multiplex-1.9.9 { db close } {} do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown } {SQLITE_OK} @@ -89,10 +89,9 @@ do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown } {SQLITE_OK} do_test multiplex-1.10.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK} do_test multiplex-1.10.2 { sqlite3 db test.db } {} do_test multiplex-1.10.3 { lindex [ catchsql { SELECT multiplex_control(2, 32768); } ] 0 } {0} -do_test multiplex-1.10.4 { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 } {1} -do_test multiplex-1.10.5 { lindex [ catchsql { SELECT multiplex_control(2, -1); } ] 0 } {1} +do_test multiplex-1.10.4 { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 } {0} do_test multiplex-1.10.6 { lindex [ catchsql { SELECT multiplex_control(2, 31); } ] 0 } {0} -do_test multiplex-1.10.7 { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 } {1} +do_test multiplex-1.10.7 { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 } {0} do_test multiplex-1.10.8 { lindex [ catchsql { SELECT multiplex_control(2, 1073741824); } ] 0 } {0} do_test multiplex-1.10.9 { db close } {} do_test multiplex-1.10.10 { sqlite3_multiplex_shutdown } {SQLITE_OK} @@ -146,8 +145,9 @@ do_test multiplex-1.13.7 { sqlite3_multiplex_shutdown } sqlite3_multiplex_initialize "" 1 multiplex_set db main 32768 16 +forcedelete test.x do_test multiplex-2.1.2 { - sqlite3 db test.db + sqlite3 db test.x execsql { PRAGMA page_size=1024; PRAGMA auto_vacuum=OFF; @@ -159,7 +159,7 @@ do_test multiplex-2.1.2 { INSERT INTO t1 VALUES(2, randomblob(1100)); } } {} -do_test multiplex-2.1.3 { file size [multiplex_name test.db 0] } {4096} +do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096} do_test multiplex-2.1.4 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} @@ -167,10 +167,10 @@ do_test multiplex-2.1.4 { do_test multiplex-2.2.1 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} -do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144} +do_test multiplex-2.2.3 { file size [multiplex_name test.x 0] } {6144} do_test multiplex-2.3.1 { - sqlite3 db2 test2.db + sqlite3 db2 test2.x db2 close } {} @@ -181,7 +181,7 @@ do_test multiplex-2.4.1 { do_test multiplex-2.4.2 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} -do_test multiplex-2.4.4 { file size [multiplex_name test.db 0] } {7168} +do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168} do_test multiplex-2.4.99 { db close sqlite3_multiplex_shutdown @@ -189,9 +189,9 @@ do_test multiplex-2.4.99 { do_test multiplex-2.5.1 { - multiplex_delete test.db + multiplex_delete test.x sqlite3_multiplex_initialize "" 1 - sqlite3 db test.db + sqlite3 db test.x multiplex_set db main 4096 16 } {SQLITE_OK} @@ -236,8 +236,8 @@ do_test multiplex-2.5.8 { db eval {SELECT a,length(b) FROM t1 WHERE a=4} } {4 4000} -do_test multiplex-2.5.9 { file size [multiplex_name test.db 0] } [list $g_chunk_size] -do_test multiplex-2.5.10 { file size [multiplex_name test.db 1] } [list $g_chunk_size] +do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size] +do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size] do_test multiplex-2.5.99 { db close @@ -514,7 +514,7 @@ do_test multiplex-5.4.1 { file mkdir test.db list [catch { sqlite3 db test.db } msg] $msg } {1 {unable to open database file}} -catch { file delete test.db } +catch { delete_file test.db } do_faultsim_test multiplex-5.5 -prep { catch { sqlite3_multiplex_shutdown } @@ -523,50 +523,6 @@ do_faultsim_test multiplex-5.5 -prep { multiplex_set db main 32768 16 } -# test that mismatch filesize is detected -# -# Do not run this test if $::G(perm:presql) is set. If it is set, then the -# expected IO error will occur within the Tcl [sqlite3] wrapper, not within -# the first SQL statement executed below. This breaks the test case. -# -if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} { - set all_journal_modes {delete persist truncate memory off} - foreach jmode $all_journal_modes { - do_test multiplex-5.6.1.$jmode { - sqlite3_multiplex_shutdown - multiplex_delete test.db - sqlite3 db test.db - db eval { - PRAGMA page_size = 1024; - PRAGMA auto_vacuum = off; - } - db eval "PRAGMA journal_mode = $jmode;" - } $jmode - do_test multiplex-5.6.2.$jmode { - execsql { - CREATE TABLE t1(a, b); - INSERT INTO t1 VALUES(1, randomblob(15000)); - INSERT INTO t1 VALUES(2, randomblob(15000)); - INSERT INTO t1 VALUES(3, randomblob(15000)); - INSERT INTO t1 VALUES(4, randomblob(15000)); - INSERT INTO t1 VALUES(5, randomblob(15000)); - } - db close - sqlite3_multiplex_initialize "" 1 - sqlite3 db test.db - multiplex_set db main 4096 16 - } {SQLITE_OK} - do_test multiplex-5.6.3.$jmode { - catchsql { - INSERT INTO t1 VALUES(6, randomblob(15000)); - } - } {1 {disk I/O error}} - do_test multiplex-5.6.4.$jmode { - db close - } {} - } -} - #------------------------------------------------------------------------- # Test that you can vacuum a multiplex'ed DB. @@ -575,8 +531,9 @@ ifcapable vacuum { sqlite3_multiplex_shutdown do_test multiplex-6.0.0 { multiplex_delete test.db + multiplex_delete test.x sqlite3_multiplex_initialize "" 1 - sqlite3 db test.db + sqlite3 db test.x multiplex_set db main 4096 16 } {SQLITE_OK} @@ -592,8 +549,8 @@ do_test multiplex-6.1.0 { INSERT INTO t1 VALUES(2, randomblob($g_chunk_size)); } } {} -do_test multiplex-6.2.1 { file size [multiplex_name test.db 0] } [list $g_chunk_size] -do_test multiplex-6.2.2 { file size [multiplex_name test.db 1] } [list $g_chunk_size] +do_test multiplex-6.2.1 { file size [multiplex_name test.x 0] } [list $g_chunk_size] +do_test multiplex-6.2.2 { file size [multiplex_name test.x 1] } [list $g_chunk_size] do_test multiplex-6.3.0 { execsql { VACUUM } @@ -601,7 +558,7 @@ do_test multiplex-6.3.0 { do_test multiplex-6.99 { db close - multiplex_delete test.db + multiplex_delete test.x sqlite3_multiplex_shutdown } {SQLITE_OK} diff --git a/test/nan.test b/test/nan.test index 3257a439..df3f65b8 100644 --- a/test/nan.test +++ b/test/nan.test @@ -320,6 +320,52 @@ do_realnum_test nan-4.20 { db eval {SELECT x, typeof(x) FROM t1} } {inf real} +do_realnum_test nan-4.30 { + db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES('2.5e+9999'); + SELECT x, typeof(x) FROM t1; + } +} {inf real} +do_realnum_test nan-4.31 { + db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES('2.5e+10000'); + SELECT x, typeof(x) FROM t1; + } +} {inf real} + +do_realnum_test nan-4.32 { + db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES('2.5e-9999'); + SELECT x, typeof(x) FROM t1; + } +} {0.0 real} +do_realnum_test nan-4.33 { + db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES('2.5e-10000'); + SELECT x, typeof(x) FROM t1; + } +} {0.0 real} +do_realnum_test nan-4.34 { + db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES('2.5e2147483650'); + SELECT x, typeof(x) FROM t1; + } +} {inf real} +do_realnum_test nan-4.35 { + db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES('2.5e-2147483650'); + SELECT x, typeof(x) FROM t1; + } +} {0.0 real} + + + finish_test diff --git a/test/notify1.test b/test/notify1.test index 1cfb36fe..be6a1225 100644 --- a/test/notify1.test +++ b/test/notify1.test @@ -140,7 +140,7 @@ do_test notify1-2.2.5 { do_test notify1-2.3.1 { db close db2 close - file delete -force test.db test2.db test3.db + forcedelete test.db test2.db test3.db foreach con {db db2 db3} { sqlite3 $con test.db $con eval { ATTACH 'test2.db' AS aux2 } @@ -294,7 +294,7 @@ do_malloc_test notify1-5 -tclprep { # db close do_test notify1-6.1.1 { - file delete -force test.db test2.db + forcedelete test.db test2.db foreach conn {db db2 db3} { sqlite3 $conn test.db execsql { ATTACH 'test2.db' AS two } $conn diff --git a/test/notify2.test b/test/notify2.test index bfb9af81..4016b6db 100644 --- a/test/notify2.test +++ b/test/notify2.test @@ -167,7 +167,7 @@ foreach {iTest xStep xPrepare} { 1 sqlite3_blocking_step sqlite3_blocking_prepare_v2 2 sqlite3_step sqlite3_nonblocking_prepare_v2 } { - file delete -force test.db test2.db test3.db + forcedelete test.db test2.db test3.db set ThreadSetup "set xStep $xStep;set xPrepare $xPrepare;set nSecond $nSecond" diff --git a/test/notify3.test b/test/notify3.test index 0d06ce19..446f0107 100644 --- a/test/notify3.test +++ b/test/notify3.test @@ -25,7 +25,7 @@ ifcapable !unlock_notify||!shared_cache { set esc [sqlite3_enable_shared_cache 1] sqlite3 db test.db -file delete -force test.db2 test.db2-journal test.db2-wal +forcedelete test.db2 test.db2-journal test.db2-wal sqlite3 db2 test.db2 do_test notify3-1.1 { diff --git a/test/openv2.test b/test/openv2.test index 843f8919..2a9e22d6 100644 --- a/test/openv2.test +++ b/test/openv2.test @@ -17,7 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal do_test openv2-1.1 { set rc [catch {sqlite3 db test.db -create 0} msg] lappend rc $msg diff --git a/test/oserror.test b/test/oserror.test index bdeb8684..40d2966b 100644 --- a/test/oserror.test +++ b/test/oserror.test @@ -97,23 +97,25 @@ do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c:\d*: \(\d+\) open\(.*test.db\) #-------------------------------------------------------------------------- # Tests oserror-1.* test failures in the unlink() system call. # -do_test 2.1.1 { - set ::log [list] - file mkdir test.db-wal - forcedelete test.db - list [catch { - sqlite3 dbh test.db - execsql { SELECT * FROM sqlite_master } dbh - } msg] $msg -} {1 {disk I/O error}} - -do_re_test 2.1.2 { - lindex $::log 0 -} {^os_unix.c:\d+: \(\d+\) unlink\(.*test.db-wal\) - } -do_test 2.1.3 { - catch { dbh close } - forcedelete test.db-wal -} {} +ifcapable wal { + do_test 2.1.1 { + set ::log [list] + file mkdir test.db-wal + forcedelete test.db + list [catch { + sqlite3 dbh test.db + execsql { SELECT * FROM sqlite_master } dbh + } msg] $msg + } {1 {disk I/O error}} + + do_re_test 2.1.2 { + lindex $::log 0 + } {^os_unix.c:\d+: \(\d+\) unlink\(.*test.db-wal\) - } + do_test 2.1.3 { + catch { dbh close } + forcedelete test.db-wal + } {} +} test_syscall reset diff --git a/test/pager1.test b/test/pager1.test index 136ca05f..0226fe49 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -452,7 +452,7 @@ do_test pager1.4.2.2 { } {4 ok} do_test pager1.4.2.3 { faultsim_restore_and_reopen - foreach f [glob test.db-mj*] { file delete -force $f } + foreach f [glob test.db-mj*] { forcedelete $f } execsql { SELECT count(*) FROM t1; PRAGMA integrity_check; @@ -469,7 +469,7 @@ do_test pager1.4.2.4 { do_test pager1.4.2.5 { faultsim_restore_and_reopen hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456 - foreach f [glob test.db-mj*] { file delete -force $f } + foreach f [glob test.db-mj*] { forcedelete $f } execsql { SELECT count(*) FROM t1; PRAGMA integrity_check; @@ -649,7 +649,7 @@ foreach {tn1 tcl} { # do_test pager1-4.4.$tn.7 { faultsim_restore_and_reopen $prefix - foreach f [glob ${prefix}-mj*] { file delete -force $f } + foreach f [glob ${prefix}-mj*] { forcedelete $f } execsql "ATTACH '${prefix}2' AS aux" } {} do_execsql_test pager1-4.4.$tn.8 { @@ -664,7 +664,7 @@ foreach {tn1 tcl} { } db close tv delete -file delete -force $dirname +forcedelete $dirname # Set up a VFS to make a copy of the file-system just before deleting a @@ -882,7 +882,7 @@ do_test pager1.4.7.3 { db close catch {file attributes test.db-journal -permissions rw-rw-rw-} catch {file attributes test.db-journal -readonly 0} - file delete test.db-journal + delete_file test.db-journal file exists test.db-journal } {0} @@ -1766,6 +1766,10 @@ do_multiclient_test tn { # + Page 0, # + A page with a page number greater than (2^31-1). # +# These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In +# that case IO errors are sometimes reported instead of SQLITE_CORRUPT. +# +ifcapable !direct_read { do_test pager1-18.1 { faultsim_delete_and_reopen db func a_string a_string @@ -1841,6 +1845,7 @@ do_test pager1-18.6 { sqlite3 db test.db catchsql { SELECT length(x) FROM t1 } } {1 {database disk image is malformed}} +} do_test pager1-19.1 { sqlite3 db "" @@ -1992,31 +1997,33 @@ ifcapable wal { # pager1-22.1.*: is a no-op on a non-WAL db, and # pager1-22.2.*: does not cause xSync calls with a synchronous=off db. # -do_test pager1-22.1.1 { - faultsim_delete_and_reopen - execsql { - CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); - INSERT INTO ko DEFAULT VALUES; - } - execsql { PRAGMA wal_checkpoint } -} {0 -1 -1} -do_test pager1-22.2.1 { - testvfs tv -default 1 - tv filter xSync - tv script xSyncCb - proc xSyncCb {args} {incr ::synccount} - set ::synccount 0 - sqlite3 db test.db - execsql { - PRAGMA synchronous = off; - PRAGMA journal_mode = WAL; - INSERT INTO ko DEFAULT VALUES; - } - execsql { PRAGMA wal_checkpoint } - set synccount -} {0} -db close -tv delete +ifcapable wal { + do_test pager1-22.1.1 { + faultsim_delete_and_reopen + execsql { + CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); + INSERT INTO ko DEFAULT VALUES; + } + execsql { PRAGMA wal_checkpoint } + } {0 -1 -1} + do_test pager1-22.2.1 { + testvfs tv -default 1 + tv filter xSync + tv script xSyncCb + proc xSyncCb {args} {incr ::synccount} + set ::synccount 0 + sqlite3 db test.db + execsql { + PRAGMA synchronous = off; + PRAGMA journal_mode = WAL; + INSERT INTO ko DEFAULT VALUES; + } + execsql { PRAGMA wal_checkpoint } + set synccount + } {0} + db close + tv delete +} #------------------------------------------------------------------------- # Tests for changing journal mode. @@ -2368,8 +2375,8 @@ do_test pager1-29.2 { # do_test pager1-30.1 { db close - file delete test.db - file delete test.db-journal + delete_file test.db + delete_file test.db-journal set fd [open test.db-journal w] seek $fd [expr 512+1032*2] puts -nonewline $fd x @@ -2409,8 +2416,8 @@ do_test pager1-31.1 { BEGIN; UPDATE t1 SET y = randomblob(1499); } - file copy test.db test.db2 - file copy test.db-journal test.db2-journal + copy_file test.db test.db2 + copy_file test.db-journal test.db2-journal hexio_write test.db2-journal 24 00000000 sqlite3 db2 test.db2 @@ -2418,5 +2425,43 @@ do_test pager1-31.1 { } {ok} } +#------------------------------------------------------------------------- +# Test that a database file can be "pre-hinted" to a certain size and that +# subsequent spilling of the pager cache does not result in the database +# file being shrunk. +# +catch {db close} +forcedelete test.db + +do_test pager1-32.1 { + sqlite3 db test.db + execsql { + CREATE TABLE t1(x, y); + } + db close + sqlite3 db test.db + execsql { + BEGIN; + INSERT INTO t1 VALUES(1, randomblob(10000)); + } + file_control_chunksize_test db main 1024 + file_control_sizehint_test db main 20971520; # 20MB + execsql { + PRAGMA cache_size = 10; + INSERT INTO t1 VALUES(1, randomblob(10000)); + INSERT INTO t1 VALUES(2, randomblob(10000)); + INSERT INTO t1 SELECT x+2, randomblob(10000) from t1; + INSERT INTO t1 SELECT x+4, randomblob(10000) from t1; + INSERT INTO t1 SELECT x+8, randomblob(10000) from t1; + INSERT INTO t1 SELECT x+16, randomblob(10000) from t1; + SELECT count(*) FROM t1; + COMMIT; + } + db close + file size test.db +} {20971520} + +# Cleanup 20MB file left by the previous test. +forcedelete test.db finish_test diff --git a/test/pagerfault.test b/test/pagerfault.test index ced6da3b..e04e97e4 100644 --- a/test/pagerfault.test +++ b/test/pagerfault.test @@ -233,7 +233,7 @@ do_faultsim_test pagerfault-5.2 -prep { do_faultsim_test pagerfault-5.3 -faults oom-transient -prep { faultsim_restore_and_reopen db func a_string a_string - file delete -force test2.db test2.db-journal test2.db-wal + forcedelete test2.db test2.db-journal test2.db-wal execsql { PRAGMA journal_mode = PERSIST; ATTACH 'test2.db' AS aux; @@ -641,7 +641,7 @@ do_test pagerfault-13-pre1 { COMMIT; } db close - file delete -force test.db + forcedelete test.db faultsim_save } {} do_faultsim_test pagerfault-13 -prep { @@ -1106,7 +1106,7 @@ do_faultsim_test pagerfault-22 -prep { # do_faultsim_test pagerfault-23 -prep { sqlite3 db :memory: - foreach f [glob -nocomplain test.db*] { file delete -force $f } + foreach f [glob -nocomplain test.db*] { forcedelete $f } db eval { ATTACH 'test.db2' AS aux; CREATE TABLE t1(a, b); diff --git a/test/pageropt.test b/test/pageropt.test index 1c634f64..82311965 100644 --- a/test/pageropt.test +++ b/test/pageropt.test @@ -17,7 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable {!pager_pragmas||secure_delete} { +ifcapable {!pager_pragmas||secure_delete||direct_read} { finish_test return } diff --git a/test/pagesize.test b/test/pagesize.test index af2c017b..0eebbbb7 100644 --- a/test/pagesize.test +++ b/test/pagesize.test @@ -42,7 +42,7 @@ do_test pagesize-1.3 { do_test pagesize-1.4 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { PRAGMA page_size=511; @@ -99,7 +99,7 @@ foreach PGSZ {512 2048 4096 8192} { } do_test pagesize-2.$PGSZ.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql "PRAGMA page_size=$PGSZ" execsql { @@ -190,7 +190,7 @@ foreach PGSZ {512 2048 4096 8192} { integrity_check pagesize-2.$PGSZ.17 db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db do_test pagesize-2.$PGSZ.30 { execsql " @@ -203,7 +203,7 @@ foreach PGSZ {512 2048 4096 8192} { } [list 1024 $PGSZ] db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db do_test pagesize-2.$PGSZ.40 { execsql " diff --git a/test/pcache2.test b/test/pcache2.test index 14df52eb..77e7a261 100644 --- a/test/pcache2.test +++ b/test/pcache2.test @@ -16,7 +16,6 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl - # Set up a pcache memory pool so that we can easily track how many # pages are being used for cache. # @@ -34,13 +33,13 @@ do_test pcache2-1.1 { # Open up two database connections to separate files. # do_test pcache2-1.2 { - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db db eval {PRAGMA cache_size=10} lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 1 } {2} do_test pcache2-1.3 { - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal sqlite3 db2 test2.db db2 eval {PRAGMA cache_size=50} lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 1 diff --git a/test/permutations.test b/test/permutations.test index 22e2189d..7c3b026c 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -111,7 +111,7 @@ set allquicktests [test_set $alltests -exclude { thread003.test thread004.test thread005.test trans2.test vacuum3.test incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test vtab_err.test walslow.test walcrash.test - walthread.test rtree3.test + walthread.test rtree3.test indexfault.test }] if {[info exists ::env(QUICKTEST_INCLUDE)]} { set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)] @@ -180,10 +180,12 @@ test_suite "fts3" -prefix "" -description { fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test fts3near.test fts3query.test fts3shared.test fts3snippet.test fts3sort.test - fts3fault.test fts3malloc.test fts3matchinfo.test - fts3aux1.test fts3comp1.test fts3auto.test + fts4aa.test fts4content.test + fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test + fts3corrupt2.test + fts3first.test } @@ -520,7 +522,7 @@ test_suite "inmemory_journal" -description { # the number of fsync() calls. pager.test exclusive.test jrnlmode.test sync.test misc1.test journal1.test conflict.test crash8.test tkt3457.test io.test - journal3.test + journal3.test 8_3_names.test pager1.test async4.test corrupt.test filefmt.test pager2.test corrupt5.test corruptA.test pageropt.test @@ -529,7 +531,7 @@ test_suite "inmemory_journal" -description { stmt.test # WAL mode is different. - wal* tkt-2d1a5c67d.test + wal* tkt-2d1a5c67d.test backcompat.test }] ifcapable mem3 { @@ -726,7 +728,7 @@ test_suite "journaltest" -description { unregister_jt_vfs } -files [test_set $::allquicktests -exclude { wal* incrvacuum.test ioerr.test corrupt4.test io.test crash8.test - async4.test bigfile.test + async4.test bigfile.test backcompat.test }] if {[info commands register_demovfs] != ""} { @@ -776,6 +778,15 @@ test_suite "no_optimization" -description { optimization_control $::dbhandle all 0 } +test_suite "prepare" -description { + Run tests with the db connection using sqlite3_prepare() instead of _v2(). +} -dbconfig { + db_use_legacy_prepare $::dbhandle 1 + #$::dbhandle cache size 0 +} -files [ + test_set $allquicktests -exclude *malloc* *ioerr* *fault* +] + # End of tests ############################################################################# @@ -856,4 +867,3 @@ if {[info script] == $argv0} { main $argv finish_test } - diff --git a/test/pragma.test b/test/pragma.test index 4b441829..0cad25a3 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -51,8 +51,8 @@ ifcapable !pragma { # that the "all.test" script does. # db close -file delete test.db test.db-journal -file delete test3.db test3.db-journal +delete_file test.db test.db-journal +delete_file test3.db test3.db-journal sqlite3 db test.db; set DB [sqlite3_connection_pointer db] @@ -221,8 +221,8 @@ do_test pragma-1.18 { # Test modifying the safety_level of an attached database. ifcapable pager_pragmas&&attach { do_test pragma-2.1 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { ATTACH 'test2.db' AS aux; } @@ -255,7 +255,7 @@ ifcapable pager_pragmas&&attach { # do_test pragma-3.1 { db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db execsql { PRAGMA auto_vacuum=OFF; @@ -312,7 +312,7 @@ ifcapable attach { # do_test pragma-3.8 { execsql {DETACH t2} - file delete -force testerr.db testerr.db-journal + forcedelete testerr.db testerr.db-journal set out [open testerr.db w] fconfigure $out -translation binary set in [open test.db r] @@ -329,6 +329,9 @@ ifcapable attach { do_test pragma-3.8.1 { execsql {PRAGMA quick_check} } {ok} + do_test pragma-3.8.2 { + execsql {PRAGMA QUICK_CHECK} + } {ok} do_test pragma-3.9 { execsql { ATTACH 'testerr.db' AS t2; @@ -419,7 +422,7 @@ Page 6 is never used} {rowid 1 missing from index i2}} } do_test pragma-3.19 { catch {db close} - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db db eval {PRAGMA integrity_check} } {ok} @@ -741,8 +744,8 @@ do_test pragma-8.1.10 { } SQLITE_SCHEMA # Make sure the schema-version can be manipulated in an attached database. -file delete -force test2.db -file delete -force test2.db-journal +forcedelete test2.db +forcedelete test2.db-journal ifcapable attach { do_test pragma-8.1.11 { execsql { @@ -1205,7 +1208,7 @@ do_test pragma-13.1 { ifcapable pager_pragmas { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db do_test pragma-14.1 { @@ -1219,6 +1222,9 @@ ifcapable pager_pragmas { PRAGMA page_count; } } {2} + do_test pragma-14.2uc { + execsql {pragma PAGE_COUNT} + } {2} do_test pragma-14.3 { execsql { @@ -1227,6 +1233,9 @@ ifcapable pager_pragmas { PRAGMA page_count; } } {3} + do_test pragma-14.3uc { + execsql {pragma PAGE_COUNT} + } {3} do_test pragma-14.4 { set page_size [db one {pragma page_size}] @@ -1241,7 +1250,7 @@ ifcapable pager_pragmas { } {2} do_test pragma-14.6 { - file delete -force test2.db + forcedelete test2.db sqlite3 db2 test2.db execsql { PRAGMA auto_vacuum = 0; @@ -1256,6 +1265,9 @@ ifcapable pager_pragmas { PRAGMA aux.page_count; } } {5} + do_test pragma-14.6uc { + execsql {pragma AUX.PAGE_COUNT} + } {5} } # Test that the value set using the cache_size pragma is not reset when the diff --git a/test/pragma2.test b/test/pragma2.test index 87c3c5d0..1111a984 100644 --- a/test/pragma2.test +++ b/test/pragma2.test @@ -33,8 +33,8 @@ ifcapable !pragma||!schema_pragmas { # that the "all.test" script does. # db close -file delete test.db test.db-journal -file delete test3.db test3.db-journal +delete_file test.db test.db-journal +delete_file test3.db test3.db-journal sqlite3 db test.db; set DB [sqlite3_connection_pointer db] db eval {PRAGMA auto_vacuum=0} @@ -61,8 +61,8 @@ do_test pragma2-1.4 { } } {1} -file delete -force test2.db -file delete -force test2.db-journal +forcedelete test2.db +forcedelete test2.db-journal ifcapable attach { do_test pragma2-2.1 { diff --git a/test/printf.test b/test/printf.test index 100ce96b..73222720 100644 --- a/test/printf.test +++ b/test/printf.test @@ -3547,7 +3547,7 @@ do_test printf-4.16 { do_test printf-5.1 { set x [sqlite3_mprintf_str {%d %d %100000s} 0 0 {Hello}] string length $x -} {344} +} {100004} do_test printf-5.2 { sqlite3_mprintf_str {%d %d (%-10.10s) %} -9 -10 {HelloHelloHello} } {-9 -10 (HelloHello) %} diff --git a/test/quota.test b/test/quota.test index d7601e0e..49b403f1 100644 --- a/test/quota.test +++ b/test/quota.test @@ -123,7 +123,7 @@ proc quota_check {filename limitvar size} { } do_test quota-3.1.1 { - file delete -force test.db + forcedelete test.db sqlite3_quota_initialize "" 1 sqlite3_quota_set *test.db 4096 quota_check } {SQLITE_OK} @@ -158,7 +158,7 @@ do_test quota-3.1.6 { } {SQLITE_OK} do_test quota-3.2.1 { - file delete force test.db test2.db + delete_file force test.db test2.db sqlite3_quota_set * 4096 {} sqlite3 db1a test.db @@ -223,7 +223,7 @@ do_test quota-3.2.X { } {SQLITE_OK} #------------------------------------------------------------------------- -# Quotas are deleted when unused and when there limit is set to zero +# Quotas are deleted when unused and when their limit is set to zero # # Return a list of all currently defined quotas. Each quota is identified @@ -235,6 +235,13 @@ proc quota_list {} { } return [lsort $allq] } +proc quota_size {name} { + set allq {} + foreach q [sqlite3_quota_dump] { + if {[lindex $q 0]==$name} {return [lindex $q 2]} + } + return 0 +} do_test quota-4.1.1 { sqlite3_quota_set *test.db 0 {} @@ -257,7 +264,7 @@ do_test quota-4.1.5 { quota_list } {*test2.db} do_test quota-4.1.6 { - file delete -force test2.db test2.db-journal test2.db-wal + forcedelete test2.db test2.db-journal test2.db-wal sqlite3 db test2.db db eval {CREATE TABLE t2(x); INSERT INTO t2 VALUES('tab-t2');} quota_list @@ -329,11 +336,121 @@ do_test quota-4.3.1 { quota_list } {} +unset -nocomplain quotagroup +if {$tcl_platform(platform)=="windows"} { + set quotagroup *\\quota-test-A?.db +} else { + set quotagroup */quota-test-A?.db +} +foreach file [glob -nocomplain quota-test-A*] { + forcedelete $file +} do_test quota-4.4.1 { + set ::quota {} + sqlite3_quota_set $::quotagroup 10000 quota_callback + file delete -force ./quota-test-A1.db ./quota-test-A2.db + sqlite3 db ./quota-test-A1.db + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(5000)); + } + quota_list +} [list $quotagroup] +do_test quota-4.4.2 { + expr {$::quota==""} +} {1} +do_test quota-4.4.3 { + db close + sqlite3 db ./quota-test-A2.db + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(5000)); + } + quota_list +} [list $quotagroup] +do_test quota-4.4.4 { + expr {$::quota!=""} +} {1} +do_test quota-4.4.5 { + db close + sqlite3_quota_set $::quotagroup 0 {} + sqlite3_quota_dump +} {} +do_test quota-4.4.6 { + sqlite3_quota_set $quotagroup 10000 quota_callback + sqlite3 db quota-test-A1.db + db eval {SELECT count(*) FROM sqlite_master} + quota_size $quotagroup +} [file size quota-test-A1.db] +do_test quota-4.4.7 { + sqlite3_quota_file quota-test-A2.db + quota_size $::quotagroup +} [expr {[file size quota-test-A1.db]+[file size quota-test-A2.db]}] + +unset -nocomplain quotagroup +if {$tcl_platform(platform)=="windows"} { + set quotagroup *\\quota-test-B* +} else { + set quotagroup */quota-test-B* +} +foreach file [glob -nocomplain quota-test-B*] { + forcedelete $file +} +do_test quota-4.5.1 { + sqlite3_quota_set $::quotagroup 100000 quota_callback + quota_size $::quotagroup +} {0} +do_test quota-4.5.2 { + sqlite3_quota_file quota-test-B1.txt + quota_size $::quotagroup +} {0} +proc add_to_file {name n} { + set out [open $name a] + fconfigure $out -translation binary + puts -nonewline $out [string repeat x $n] + close $out +} +do_test quota-4.5.3 { + add_to_file quota-test-B1.txt 123 + sqlite3_quota_file quota-test-B1.txt + quota_size $::quotagroup +} {123} +do_test quota-4.5.4 { + add_to_file quota-test-B2.txt 234 + sqlite3_quota_file quota-test-B2.txt + quota_size $::quotagroup +} {357} +do_test quota-4.5.5 { + add_to_file quota-test-B1.txt 2000 + sqlite3_quota_file quota-test-B1.txt + quota_size $::quotagroup +} {2357} +do_test quota-4.5.6 { + forcedelete quota-test-B1.txt + sqlite3_quota_file quota-test-B1.txt + quota_size $::quotagroup +} {234} +do_test quota-4.5.7 { + forcedelete quota-test-B2.txt + sqlite3_quota_file quota-test-B2.txt + quota_size $::quotagroup +} {0} +do_test quota-4.5.8 { + add_to_file quota-test-B3.txt 1234 + sqlite3_quota_file quota-test-B3.txt + quota_size $::quotagroup +} {1234} +do_test quota-4.5.9 { + sqlite3_quota_set $quotagroup 0 {} + quota_size $::quotagroup +} {0} + +do_test quota-4.9.1 { + db close sqlite3_quota_set A 1000 quota_callback sqlite3_quota_shutdown } {SQLITE_OK} -do_test quota-4.4.2 { +do_test quota-4.9.2 { quota_list } {} @@ -357,7 +474,7 @@ do_faultsim_test quota-5.2 -prep { } catch { db close } -file delete -force test.db +forcedelete test.db do_test quota-5.3.prep { sqlite3 db test.db @@ -377,7 +494,7 @@ do_faultsim_test quota-5.3 -prep { do_test quota-5.4.1 { catch { db close } - file delete -force test.db + forcedelete test.db file mkdir test.db list [catch { sqlite3 db test.db } msg] $msg } {1 {unable to open database file}} diff --git a/test/releasetest.tcl b/test/releasetest.tcl index 84542bb8..77256301 100644 --- a/test/releasetest.tcl +++ b/test/releasetest.tcl @@ -155,10 +155,10 @@ array set ::Configs { array set ::Platforms { Linux-x86_64 { + "Debug-One" "checksymbols test" "Secure-Delete" test "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Update-Delete-Limit" test - "Debug-One" test "Extra-Robustness" test "Device-Two" test "Ftrapv" test @@ -177,6 +177,7 @@ array set ::Platforms { } } + # End of configuration section. ######################################################################### ######################################################################### diff --git a/test/rollback.test b/test/rollback.test index d462fc48..fc123ab9 100644 --- a/test/rollback.test +++ b/test/rollback.test @@ -88,8 +88,8 @@ if {$tcl_platform(platform) == "unix" BEGIN; INSERT INTO t3 VALUES('hello world'); } - file copy -force test.db testA.db - file copy -force test.db-journal testA.db-journal + forcecopy test.db testA.db + forcecopy test.db-journal testA.db-journal execsql { COMMIT; } diff --git a/test/savepoint.test b/test/savepoint.test index 042c5558..3bbbaaae 100644 --- a/test/savepoint.test +++ b/test/savepoint.test @@ -371,7 +371,7 @@ wal_check_journal_mode savepoint-5.5 # ifcapable {autovacuum && pragma} { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db do_test savepoint-6.1 { @@ -419,7 +419,7 @@ ifcapable {autovacuum && pragma} { # surrounding savepoints by growing and shrinking the database file. # db close -file delete -force test.db +forcedelete test.db sqlite3 db test.db do_test savepoint-7.1 { @@ -490,7 +490,7 @@ wal_check_journal_mode savepoint-7.3.3 do_test savepoint-7.4.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { PRAGMA auto_vacuum = incremental } wal_set_journal_mode @@ -640,8 +640,8 @@ set templockstate [lindex [db eval {PRAGMA lock_status}] 3] if {[wal_is_wal_mode]==0} { do_test savepoint-10.2.1 { - file delete -force test3.db - file delete -force test2.db + forcedelete test3.db + forcedelete test2.db execsql { ATTACH 'test2.db' AS aux1; ATTACH 'test3.db' AS aux2; @@ -762,7 +762,7 @@ if {[wal_is_wal_mode]==0} { # do_test savepoint-11.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { PRAGMA auto_vacuum = full; } wal_set_journal_mode @@ -868,7 +868,7 @@ wal_check_journal_mode savepoint-12.5 if {[wal_is_wal_mode]==0} { do_test savepoint-13.1 { db close - catch {file delete -force test.db} + catch {forcedelete test.db} sqlite3 db test.db execsql { BEGIN; @@ -909,7 +909,7 @@ if {[wal_is_wal_mode]==0} { } db close -file delete test.db +delete_file test.db do_multiclient_test tn { do_test savepoint-14.$tn.1 { sql1 { diff --git a/test/savepoint6.test b/test/savepoint6.test index 60fde4c2..b1d0d46f 100644 --- a/test/savepoint6.test +++ b/test/savepoint6.test @@ -246,7 +246,7 @@ foreach zSetup [list { unset -nocomplain ::aEntry catch { db close } - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal eval $zSetup sql $DATABASE_SCHEMA diff --git a/test/securedel.test b/test/securedel.test index c965069e..7ff5a628 100644 --- a/test/securedel.test +++ b/test/securedel.test @@ -26,7 +26,7 @@ do_test securedel-1.0 { db eval {PRAGMA secure_delete;} } $DEFAULT_SECDEL -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal do_test securedel-1.1 { db eval { ATTACH 'test2.db' AS db2; diff --git a/test/selectB.test b/test/selectB.test index 3fdf85c0..b9d979ac 100644 --- a/test/selectB.test +++ b/test/selectB.test @@ -355,7 +355,7 @@ for {set ii 3} {$ii <= 4} {incr ii} { SELECT DISTINCT (a/10) FROM t1 UNION ALL SELECT DISTINCT(d%2) FROM t2 ) } - } {0 1 0 1} + } {0 1 1 0} do_test selectB-$ii.20 { execsql { diff --git a/test/server1.test b/test/server1.test index 134a9f57..90673ef0 100644 --- a/test/server1.test +++ b/test/server1.test @@ -29,7 +29,7 @@ if {[llength [info command client_step]]==0 || [sqlite3 -has-codec]} { # The sample server implementation does not work right when memory # management is enabled. # -ifcapable memorymanage { +ifcapable (memorymanage||mutex_noop) { finish_test return } diff --git a/test/shared.test b/test/shared.test index 35ddf088..37564e69 100644 --- a/test/shared.test +++ b/test/shared.test @@ -27,7 +27,7 @@ set ::enable_shared_cache [sqlite3_enable_shared_cache 1] foreach av [list 0 1] { # Open the database connection and execute the auto-vacuum pragma -file delete -force test.db +forcedelete test.db sqlite3 db test.db ifcapable autovacuum { @@ -293,9 +293,9 @@ catch {db3 close} # db2.main -> ./test2.db # db2.test -> ./test.db # -file delete -force test.db -file delete -force test2.db -file delete -force test2.db-journal +forcedelete test.db +forcedelete test2.db +forcedelete test2.db-journal sqlite3 db test.db sqlite3 db2 test2.db do_test shared-$av.4.1.1 { @@ -426,7 +426,7 @@ catch {db close} # Tests shared-5.* # foreach db [list test.db test1.db test2.db test3.db] { - file delete -force $db ${db}-journal + forcedelete $db ${db}-journal } do_test shared-$av.5.1.1 { sqlite3 db1 test.db @@ -557,7 +557,7 @@ do_test shared-$av.6.1.4 { catch {db1 close} catch {db2 close} foreach f [list test.db test2.db] { - file delete -force $f ${f}-journal + forcedelete $f ${f}-journal } #-------------------------------------------------------------------------- @@ -643,7 +643,7 @@ unset -nocomplain contents # The following tests try to trick the shared-cache code into assuming # the wrong encoding for a database. # -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal ifcapable utf16 { do_test shared-$av.8.1.1 { sqlite3 db test.db @@ -675,7 +675,7 @@ ifcapable utf16 { } } {UTF-8} - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal do_test shared-$av.8.2.1 { execsql { ATTACH 'test2.db' AS aux; @@ -693,7 +693,7 @@ ifcapable utf16 { catch {db close} catch {db2 close} - file delete -force test.db test2.db + forcedelete test.db test2.db do_test shared-$av.8.3.2 { sqlite3 db test.db @@ -732,7 +732,7 @@ if 0 { catch {db close} catch {db2 close} -file delete -force test.db test2.db +forcedelete test.db test2.db #--------------------------------------------------------------------------- # The following tests - shared-9.* - test interactions between TEMP triggers @@ -772,7 +772,7 @@ do_test shared-$av.9.3 { # do_test shared-$av.10.1 { # Create a small sample database with two connections to it (db and db2). - file delete -force test.db + forcedelete test.db sqlite3 db test.db sqlite3 db2 test.db execsql { @@ -853,7 +853,7 @@ do_test shared-$av.10.11 { } {} do_test shared-$av.11.1 { - file delete -force test.db + forcedelete test.db sqlite3 db test.db sqlite3 db2 test.db execsql { @@ -916,7 +916,7 @@ do_test shared-$av.11.11 { # This tests that if it is impossible to free any pages, SQLite will # exceed the limit set by PRAGMA cache_size. -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db ifcapable pager_pragmas { do_test shared-$av.12.1 { @@ -963,7 +963,7 @@ do_test shared-$av.12.X { # database handle. This covers an extra line or two. # do_test shared-$av.13.1 { - file delete -force test2.db test3.db test4.db test5.db + forcedelete test2.db test3.db test4.db test5.db sqlite3 db :memory: execsql { ATTACH 'test2.db' AS aux2; @@ -1026,7 +1026,7 @@ do_test shared-$av.14.3 { # assert() statements in the C code. # do_test shared-$av-15.1 { - file delete -force test.db + forcedelete test.db sqlite3 db test.db -fullmutex 1 sqlite3 db2 test.db -fullmutex 1 execsql { diff --git a/test/shared2.test b/test/shared2.test index d2a0d1b0..d40c9a27 100644 --- a/test/shared2.test +++ b/test/shared2.test @@ -129,7 +129,7 @@ do_test shared2-3.2 { sqlite3_enable_shared_cache 1 } {1} -file delete -force test.db +forcedelete test.db sqlite3 db test.db do_test shared2-4.1 { diff --git a/test/shared3.test b/test/shared3.test index 8f9eae9b..783ae6a8 100644 --- a/test/shared3.test +++ b/test/shared3.test @@ -24,7 +24,7 @@ set ::enable_shared_cache [sqlite3_enable_shared_cache 1] # Ticket #1824 # do_test shared3-1.1 { - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db1 test.db db1 eval { PRAGMA encoding=UTF16; diff --git a/test/shared4.test b/test/shared4.test index f9f01738..83925b06 100644 --- a/test/shared4.test +++ b/test/shared4.test @@ -30,10 +30,10 @@ set ::enable_shared_cache [sqlite3_enable_shared_cache 1] # Prepare multiple databases in shared cache mode. # do_test shared4-1.1 { - file delete -force test1.db test1.db-journal - file delete -force test2.db test2.db-journal - file delete -force test3.db test3.db-journal - file delete -force test4.db test4.db-journal + forcedelete test1.db test1.db-journal + forcedelete test2.db test2.db-journal + forcedelete test3.db test3.db-journal + forcedelete test4.db test4.db-journal sqlite3 db1 test1.db sqlite3 db2 test2.db sqlite3 db3 test3.db diff --git a/test/shared6.test b/test/shared6.test index 4d38b22e..499cbb0e 100644 --- a/test/shared6.test +++ b/test/shared6.test @@ -235,7 +235,7 @@ do_test shared6-3.X { } {} do_test shared6-4.1 { - #file delete -force test.db test.db-journal + #forcedelete test.db test.db-journal sqlite3 db1 test.db sqlite3 db2 test.db diff --git a/test/shared7.test b/test/shared7.test index d003f0ae..5c4a1da2 100644 --- a/test/shared7.test +++ b/test/shared7.test @@ -35,7 +35,7 @@ do_test shared7-1.2 { } {1 {database is already attached}} do_test shared7-1.3 { - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal db eval { ATTACH 'test2.db' AS test2; CREATE TABLE test2.t2(y); diff --git a/test/speed3.test b/test/speed3.test index a99a6245..1beaeb74 100644 --- a/test/speed3.test +++ b/test/speed3.test @@ -116,7 +116,7 @@ proc reset_db {} { } } -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal reset_db # Set up a database in auto-vacuum mode and create a database schema. diff --git a/test/sqllimits1.test b/test/sqllimits1.test index bf4a2626..2cbad3ff 100644 --- a/test/sqllimits1.test +++ b/test/sqllimits1.test @@ -319,18 +319,22 @@ do_test sqllimits1-5.14.4 { catch {sqlite3_bind_text $::STMT 1 $::str1 -1} res set res } {SQLITE_TOOBIG} -do_test sqllimits1-5.14.5 { - catch {sqlite3_bind_text16 $::STMT 1 $::str1 -1} res - set res -} {SQLITE_TOOBIG} +ifcapable utf16 { + do_test sqllimits1-5.14.5 { + catch {sqlite3_bind_text16 $::STMT 1 $::str1 -1} res + set res + } {SQLITE_TOOBIG} +} do_test sqllimits1-5.14.6 { catch {sqlite3_bind_text $::STMT 1 $::str1 $np1} res set res } {SQLITE_TOOBIG} -do_test sqllimits1-5.14.7 { - catch {sqlite3_bind_text16 $::STMT 1 $::str1 $np1} res - set res -} {SQLITE_TOOBIG} +ifcapable utf16 { + do_test sqllimits1-5.14.7 { + catch {sqlite3_bind_text16 $::STMT 1 $::str1 $np1} res + set res + } {SQLITE_TOOBIG} +} do_test sqllimits1-5.14.8 { set n [expr {$np1-1}] catch {sqlite3_bind_text $::STMT 1 $::str1 $n} res @@ -755,7 +759,7 @@ ifcapable attach { do_test sqllimits1-12.1 { set max $::SQLITE_MAX_ATTACHED for {set i 0} {$i < ($max)} {incr i} { - file delete -force test${i}.db test${i}.db-journal + forcedelete test${i}.db test${i}.db-journal } for {set i 0} {$i < ($max)} {incr i} { execsql "ATTACH 'test${i}.db' AS aux${i}" diff --git a/test/stat.test b/test/stat.test index e1aeaa9e..21726eb2 100644 --- a/test/stat.test +++ b/test/stat.test @@ -36,7 +36,8 @@ ifcapable wal { do_execsql_test stat-0.1 { PRAGMA journal_mode = WAL; PRAGMA journal_mode = delete; - SELECT * FROM stat; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat; } {wal delete sqlite_master / 1 leaf 0 0 916 0} } @@ -50,17 +51,20 @@ do_test stat-1.0 { } {} do_test stat-1.1 { execsql { - SELECT * FROM stat WHERE name = 't1'; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat WHERE name = 't1'; } } {t1 / 2 leaf 2 10 998 5} do_test stat-1.2 { execsql { - SELECT * FROM stat WHERE name = 'i1'; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat WHERE name = 'i1'; } } {i1 / 3 leaf 2 10 1000 5} do_test stat-1.3 { execsql { - SELECT * FROM stat WHERE name = 'sqlite_master'; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat WHERE name = 'sqlite_master'; } } {sqlite_master / 1 leaf 2 77 831 40} do_test stat-1.4 { @@ -77,7 +81,8 @@ do_execsql_test stat-2.1 { INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3; INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3; INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3; - SELECT * FROM stat WHERE name != 'sqlite_master'; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat WHERE name != 'sqlite_master'; } [list \ sqlite_autoindex_t3_1 / 3 internal 3 368 623 125 \ sqlite_autoindex_t3_1 /000/ 8 leaf 8 946 46 123 \ @@ -108,7 +113,8 @@ do_execsql_test stat-3.1 { CREATE TABLE t4(x); CREATE INDEX i4 ON t4(x); INSERT INTO t4(rowid, x) VALUES(2, a_string(7777)); - SELECT * FROM stat WHERE name != 'sqlite_master'; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat WHERE name != 'sqlite_master'; } [list \ i4 / 3 leaf 1 103 905 7782 \ i4 /000+000000 9 overflow 0 1020 0 0 \ @@ -132,14 +138,15 @@ do_execsql_test stat-3.1 { do_execsql_test stat-4.1 { CREATE TABLE t5(x); CREATE INDEX i5 ON t5(x); - SELECT * FROM stat WHERE name = 't5' OR name = 'i5'; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat WHERE name = 't5' OR name = 'i5'; } [list \ i5 / 5 leaf 0 0 1016 0 \ t5 / 4 leaf 0 0 1016 0 \ ] db close -file delete -force test.db +forcedelete test.db sqlite3 db test.db register_dbstat_vtab db breakpoint @@ -149,7 +156,8 @@ do_execsql_test stat-5.1 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(zeroblob(1513)); INSERT INTO t1 VALUES(zeroblob(1514)); - SELECT * FROM stat WHERE name = 't1'; + SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload + FROM stat WHERE name = 't1'; } [list \ t1 / 2 leaf 2 993 5 1517 \ t1 /000+000000 3 overflow 0 1020 0 0 \ diff --git a/test/subquery2.test b/test/subquery2.test new file mode 100644 index 00000000..04200046 --- /dev/null +++ b/test/subquery2.test @@ -0,0 +1,86 @@ +# 2011 September 16 +# +# 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 correlated subqueries +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !subquery { + finish_test + return +} + +do_test subquery2-1.1 { + execsql { + BEGIN; + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(3,4); + INSERT INTO t1 VALUES(5,6); + INSERT INTO t1 VALUES(7,8); + CREATE TABLE t2(c,d); + INSERT INTO t2 VALUES(1,1); + INSERT INTO t2 VALUES(3,9); + INSERT INTO t2 VALUES(5,25); + INSERT INTO t2 VALUES(7,49); + CREATE TABLE t3(e,f); + INSERT INTO t3 VALUES(1,1); + INSERT INTO t3 VALUES(3,27); + INSERT INTO t3 VALUES(5,125); + INSERT INTO t3 VALUES(7,343); + COMMIT; + } + execsql { + SELECT a FROM t1 + WHERE b IN (SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1 3 5 7} +do_test subquery2-1.2 { + execsql { + CREATE INDEX t1b ON t1(b); + SELECT a FROM t1 + WHERE b IN (SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1 3 5 7} + +do_test subquery2-1.11 { + execsql { + SELECT a FROM t1 + WHERE +b=(SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1} +do_test subquery2-1.12 { + execsql { + SELECT a FROM t1 + WHERE b=(SELECT x+1 FROM (SELECT DISTINCT f/(a*a) AS x FROM t3)); + } +} {1} + +do_test subquery2-1.21 { + execsql { + SELECT a FROM t1 + WHERE +b=(SELECT x+1 FROM + (SELECT DISTINCT f/d AS x FROM t2 JOIN t3 ON d*a=f)) + } +} {1 3 5 7} +do_test subquery2-1.22 { + execsql { + SELECT a FROM t1 + WHERE b=(SELECT x+1 FROM + (SELECT DISTINCT f/d AS x FROM t2 JOIN t3 ON d*a=f)) + } +} {1 3 5 7} + + +finish_test diff --git a/test/superlock.test b/test/superlock.test index b12863f7..8155d929 100644 --- a/test/superlock.test +++ b/test/superlock.test @@ -48,6 +48,11 @@ do_execsql_test 1.1 { PRAGMA journal_mode = DELETE; } {delete} +ifcapable !wal { + finish_test + return +} + do_test 1.2 { sqlite3demo_superlock unlock test.db } {unlock} do_catchsql_test 1.3 { SELECT * FROM t1 } {1 {database is locked}} do_test 1.4 { unlock } {} diff --git a/test/sync.test b/test/sync.test index 4b02ad72..14252b5c 100644 --- a/test/sync.test +++ b/test/sync.test @@ -42,8 +42,8 @@ proc cond_incr_sync_count {adj} { do_test sync-1.1 { set sqlite_sync_count 0 - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { PRAGMA fullfsync=OFF; CREATE TABLE t1(a,b); diff --git a/test/syscall.test b/test/syscall.test index 4442612a..201bd636 100644 --- a/test/syscall.test +++ b/test/syscall.test @@ -59,7 +59,7 @@ do_test 2.1.2 { test_syscall exists nosuchcall } 0 foreach s { open close access getcwd stat fstat ftruncate fcntl read pread write pwrite fchmod fallocate - pread64 pwrite64 + pread64 pwrite64 unlink openDirectory } { if {[test_syscall exists $s]} {lappend syscall_list $s} } diff --git a/test/table.test b/test/table.test index 5fa91166..4826cb92 100644 --- a/test/table.test +++ b/test/table.test @@ -260,6 +260,18 @@ do_test table-5.2 { catchsql {DROP TABLE IF EXISTS sqlite_master} } {1 {table sqlite_master may not be dropped}} +# Dropping sqlite_statN tables is OK. +# +do_test table-5.2.1 { + db eval { + ANALYZE; + DROP TABLE IF EXISTS sqlite_stat1; + DROP TABLE IF EXISTS sqlite_stat2; + DROP TABLE IF EXISTS sqlite_stat3; + SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_stat*'; + } +} {} + # Make sure an EXPLAIN does not really create a new table # do_test table-5.3 { @@ -667,8 +679,8 @@ ifcapable attach { # Now attach a database and ensure that a table can be created in the # attached database whilst in a callback from a query on the main database. do_test table-14.3 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { ATTACH 'test2.db' as aux; } diff --git a/test/tclsqlite.test b/test/tclsqlite.test index 8db04ebf..0ed06024 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -617,5 +617,16 @@ ifcapable tclvar { } {31323334 blob} } +db func xCall xCall +proc xCall {} { return "value" } +do_execsql_test tcl-14.1 { + CREATE TABLE t6(x); + INSERT INTO t6 VALUES(1); +} +do_test tcl-14.2 { + db one {SELECT x FROM t6 WHERE xCall()!='value'} +} {} + + finish_test diff --git a/test/temptable.test b/test/temptable.test index ad85f7e9..5eeb0f57 100644 --- a/test/temptable.test +++ b/test/temptable.test @@ -292,6 +292,7 @@ do_test temptable-5.1 { execsql { CREATE TEMP TABLE mask(a,b,c) } db2 + if {[permutation]=="prepare"} { db2 cache flush } execsql { CREATE INDEX mask ON t2(x); SELECT * FROM t2; @@ -403,7 +404,7 @@ do_test temptable-6.8 { } } {1 {no such table: t9}} -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal ifcapable attach { do_test temptable-7.1 { catchsql { @@ -414,14 +415,14 @@ ifcapable attach { } # Need to do the following for tcl 8.5 on mac. On that configuration, the -# -readonly flag is taken so seriously that a subsequent [file delete -force] +# -readonly flag is taken so seriously that a subsequent [forcedelete] # (required before the next test file can be executed) will fail. # catch {file attributes test.db -readonly 0} do_test temptable-8.0 { db close - catch {file delete -force test.db} + catch {forcedelete test.db} sqlite3 db test.db } {} do_test temptable-8.1 { diff --git a/test/temptrigger.test b/test/temptrigger.test index ececc4a8..ed1efb91 100644 --- a/test/temptrigger.test +++ b/test/temptrigger.test @@ -157,8 +157,8 @@ sqlite3_enable_shared_cache $::enable_shared_cache # temptrigger-3.4: Check that the temp trigger can be dropped without error. # do_test temptrigger-3.1 { - catch { file delete -force test2.db test2.db-journal } - catch { file delete -force test.db test.db-journal } + catch { forcedelete test2.db test2.db-journal } + catch { forcedelete test.db test.db-journal } sqlite3 db test.db sqlite3 db2 test2.db execsql { CREATE TABLE t2(a, b) } db2 diff --git a/test/tester.tcl b/test/tester.tcl index 8624821a..3c34b45d 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -20,7 +20,9 @@ # Commands to manipulate the db and the file-system at a high level: # # copy_file FROM TO -# drop_all_table ?DB? +# delete_file FILENAME +# drop_all_tables ?DB? +# forcecopy FROM TO # forcedelete FILENAME # # Test the capability of the SQLite version built into the interpreter to @@ -123,6 +125,121 @@ if {[info command sqlite_orig]==""} { } } +proc getFileRetries {} { + if {![info exists ::G(file-retries)]} { + # + # NOTE: Return the default number of retries for [file] operations. A + # value of zero or less here means "disabled". + # + return [expr {$::tcl_platform(platform) eq "windows" ? 10 : 0}] + } + return $::G(file-retries) +} + +proc getFileRetryDelay {} { + if {![info exists ::G(file-retry-delay)]} { + # + # NOTE: Return the default number of milliseconds to wait when retrying + # failed [file] operations. A value of zero or less means "do not + # wait". + # + return 100; # TODO: Good default? + } + return $::G(file-retry-delay) +} + +# Copy file $from into $to. This is used because some versions of +# TCL for windows (notably the 8.4.1 binary package shipped with the +# current mingw release) have a broken "file copy" command. +# +proc copy_file {from to} { + do_copy_file false $from $to +} + +proc forcecopy {from to} { + do_copy_file true $from $to +} + +proc do_copy_file {force from to} { + set nRetry [getFileRetries] ;# Maximum number of retries. + set nDelay [getFileRetryDelay] ;# Delay in ms before retrying. + + # On windows, sometimes even a [file copy -force] can fail. The cause is + # usually "tag-alongs" - programs like anti-virus software, automatic backup + # tools and various explorer extensions that keep a file open a little longer + # than we expect, causing the delete to fail. + # + # The solution is to wait a short amount of time before retrying the copy. + # + if {$nRetry > 0} { + for {set i 0} {$i<$nRetry} {incr i} { + set rc [catch { + if {$force} { + file copy -force $from $to + } else { + file copy $from $to + } + } msg] + if {$rc==0} break + if {$nDelay > 0} { after $nDelay } + } + if {$rc} { error $msg } + } else { + if {$force} { + file copy -force $from $to + } else { + file copy $from $to + } + } +} + +# Delete a file or directory +# +proc delete_file {args} { + do_delete_file false {*}$args +} + +proc forcedelete {args} { + do_delete_file true {*}$args +} + +proc do_delete_file {force args} { + set nRetry [getFileRetries] ;# Maximum number of retries. + set nDelay [getFileRetryDelay] ;# Delay in ms before retrying. + + foreach filename $args { + # On windows, sometimes even a [file delete -force] can fail just after + # a file is closed. The cause is usually "tag-alongs" - programs like + # anti-virus software, automatic backup tools and various explorer + # extensions that keep a file open a little longer than we expect, causing + # the delete to fail. + # + # The solution is to wait a short amount of time before retrying the + # delete. + # + if {$nRetry > 0} { + for {set i 0} {$i<$nRetry} {incr i} { + set rc [catch { + if {$force} { + file delete -force $filename + } else { + file delete $filename + } + } msg] + if {$rc==0} break + if {$nDelay > 0} { after $nDelay } + } + if {$rc} { error $msg } + } else { + if {$force} { + file delete -force $filename + } else { + file delete $filename + } + } + } +} + proc execpresql {handle args} { trace remove execution $handle enter [list execpresql $handle] if {[info exists ::G(perm:presql)]} { @@ -154,6 +271,8 @@ if {[info exists cmdlinearg]==0} { # --backtrace=N # --binarylog=N # --soak=N + # --file-retries=N + # --file-retry-delay=N # --start=[$permutation:]$testfile # set cmdlinearg(soft-heap-limit) 0 @@ -162,6 +281,8 @@ if {[info exists cmdlinearg]==0} { set cmdlinearg(backtrace) 10 set cmdlinearg(binarylog) 0 set cmdlinearg(soak) 0 + set cmdlinearg(file-retries) 0 + set cmdlinearg(file-retry-delay) 0 set cmdlinearg(start) "" set leftover [list] @@ -197,6 +318,14 @@ if {[info exists cmdlinearg]==0} { foreach {dummy cmdlinearg(soak)} [split $a =] break set ::G(issoak) $cmdlinearg(soak) } + {^-+file-retries=.+$} { + foreach {dummy cmdlinearg(file-retries)} [split $a =] break + set ::G(file-retries) $cmdlinearg(file-retries) + } + {^-+file-retry-delay=.+$} { + foreach {dummy cmdlinearg(file-retry-delay)} [split $a =] break + set ::G(file-retry-delay) $cmdlinearg(file-retry-delay) + } {^-+start=.+$} { foreach {dummy cmdlinearg(start)} [split $a =] break @@ -246,9 +375,9 @@ sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) # proc reset_db {} { catch {db close} - file delete -force test.db - file delete -force test.db-journal - file delete -force test.db-wal + forcedelete test.db + forcedelete test.db-journal + forcedelete test.db-wal sqlite3 db ./test.db set ::DB [sqlite3_connection_pointer db] if {[info exists ::SETUP_SQL]} { @@ -622,10 +751,10 @@ proc finalize_testing {} { } } foreach f [glob -nocomplain test.db-*-journal] { - file delete -force $f + forcedelete $f } foreach f [glob -nocomplain test.db-mj*] { - file delete -force $f + forcedelete $f } exit [expr {$nErr>0}] } @@ -740,30 +869,6 @@ proc stepsql {dbptr sql} { return $r } -# Delete a file or directory -# -proc forcedelete {args} { - foreach filename $args { - # On windows, sometimes even a [file delete -force] can fail just after - # a file is closed. The cause is usually "tag-alongs" - programs like - # anti-virus software, automatic backup tools and various explorer - # extensions that keep a file open a little longer than we expect, causing - # the delete to fail. - # - # The solution is to wait a short amount of time before retrying the - # delete. - # - set nRetry 50 ;# Maximum number of retries. - set nDelay 100 ;# Delay in ms before retrying. - for {set i 0} {$i<$nRetry} {incr i} { - set rc [catch {file delete -force $filename} msg] - if {$rc==0} break - after $nDelay - } - if {$rc} { error $msg } - } -} - # Do an integrity check of the entire database # proc integrity_check {name {db db}} { @@ -964,10 +1069,10 @@ proc do_ioerr_test {testname args} { set ::sqlite_io_error_pending 0 catch {db close} catch {db2 close} - catch {file delete -force test.db} - catch {file delete -force test.db-journal} - catch {file delete -force test2.db} - catch {file delete -force test2.db-journal} + catch {forcedelete test.db} + catch {forcedelete test.db-journal} + catch {forcedelete test2.db} + catch {forcedelete test2.db-journal} set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db] sqlite3_extended_result_codes $::DB $::ioerropts(-erc) if {[info exists ::ioerropts(-tclprep)]} { @@ -1241,24 +1346,6 @@ proc memdebug_log_sql {{filename mallocs.sql}} { close $fd } -# Copy file $from into $to. This is used because some versions of -# TCL for windows (notably the 8.4.1 binary package shipped with the -# current mingw release) have a broken "file copy" command. -# -proc copy_file {from to} { - if {$::tcl_platform(platform)=="unix"} { - file copy -force $from $to - } else { - set f [open $from] - fconfigure $f -translation binary - set t [open $to w] - fconfigure $t -translation binary - puts -nonewline $t [read $f [file size $from]] - close $t - close $f - } -} - # Drop all tables in database [db] proc drop_all_tables {{db db}} { ifcapable trigger&&foreignkey { @@ -1440,7 +1527,7 @@ proc db_save {} { foreach f [glob -nocomplain sv_test.db*] { forcedelete $f } foreach f [glob -nocomplain test.db*] { set f2 "sv_$f" - file copy -force $f $f2 + forcecopy $f $f2 } } proc db_save_and_close {} { @@ -1452,7 +1539,7 @@ proc db_restore {} { foreach f [glob -nocomplain test.db*] { forcedelete $f } foreach f2 [glob -nocomplain sv_test.db*] { set f [string range $f2 3 end] - file copy -force $f2 $f + forcecopy $f2 $f } } proc db_restore_and_reopen {{dbfile test.db}} { @@ -1462,7 +1549,7 @@ proc db_restore_and_reopen {{dbfile test.db}} { } proc db_delete_and_reopen {{file test.db}} { catch { db close } - foreach f [glob -nocomplain test.db*] { file delete -force $f } + foreach f [glob -nocomplain test.db*] { forcedelete $f } sqlite3 db $file } diff --git a/test/thread001.test b/test/thread001.test index 9b788aaf..7e0893f2 100644 --- a/test/thread001.test +++ b/test/thread001.test @@ -42,7 +42,7 @@ foreach {tn same_db shared_cache} [list \ sqlite3_enable_shared_cache $shared_cache sqlite3_enable_shared_cache $shared_cache } $shared_cache - sqlite3 db test.db -fullmutex 1 + sqlite3 db test.db -fullmutex 1 -key xyzzy set dbconfig "" if {$same_db} { @@ -77,7 +77,7 @@ foreach {tn same_db shared_cache} [list \ #sqlthread parent {puts STARTING..} set needToClose 0 if {![info exists ::DB]} { - set ::DB [sqlthread open test.db] + set ::DB [sqlthread open test.db xyzzy] #sqlthread parent "puts \"OPEN $::DB\"" set needToClose 1 } diff --git a/test/thread002.test b/test/thread002.test index b1e5f636..b39c9ae7 100644 --- a/test/thread002.test +++ b/test/thread002.test @@ -16,9 +16,11 @@ set testdir [file dirname $argv0] +set do_not_use_codec 1 source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } + db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] @@ -27,7 +29,7 @@ set ::NTHREAD 10 do_test thread002.1 { # Create 3 databases with identical schemas: for {set ii 0} {$ii < 3} {incr ii} { - file delete -force test${ii}.db + forcedelete test${ii}.db sqlite3 db test${ii}.db execsql { CREATE TABLE t1(k, v); diff --git a/test/thread003.test b/test/thread003.test index 8aa513af..8c7440c8 100644 --- a/test/thread003.test +++ b/test/thread003.test @@ -40,7 +40,7 @@ do_test thread003.1.2 { } {1} do_test thread003.1.3 { db close - file delete -force test2.db + forcedelete test2.db sqlite3 db test2.db } {} do_test thread003.1.4 { @@ -80,7 +80,7 @@ do_test thread003.2 { foreach zFile {test.db test2.db} { set SCRIPT [format { set iEnd [expr {[clock_seconds] + %d}] - set ::DB [sqlthread open %s] + set ::DB [sqlthread open %s xyzzy] # Set the cache size to 15 pages per cache. 30 available globally. execsql { PRAGMA cache_size = 15 } @@ -117,7 +117,7 @@ do_test thread003.3 { set SCRIPT [format { set iStart [clock_seconds] set iEnd [expr {[clock_seconds] + %d}] - set ::DB [sqlthread open %s] + set ::DB [sqlthread open %s xyzzy] # Set the cache size to 15 pages per cache. 30 available globally. execsql { PRAGMA cache_size = 15 } @@ -156,7 +156,7 @@ unset -nocomplain finished(2) do_test thread003.4 { thread_spawn finished(1) $thread_procs [format { set iEnd [expr {[clock_seconds] + %d}] - set ::DB [sqlthread open test.db] + set ::DB [sqlthread open test.db xyzzy] # Set the cache size to 15 pages per cache. 30 available globally. execsql { PRAGMA cache_size = 15 } diff --git a/test/thread005.test b/test/thread005.test index 9253287d..89cbfe76 100644 --- a/test/thread005.test +++ b/test/thread005.test @@ -121,7 +121,7 @@ for {set ii 2} {$ii < 500} {incr ii} { # switch or something... # -file delete -force test.db test2.db +forcedelete test.db test2.db unset -nocomplain finished do_test thread005-2.1 { diff --git a/test/tkt-2d1a5c67d.test b/test/tkt-2d1a5c67d.test index 278e1d38..bf9595f0 100644 --- a/test/tkt-2d1a5c67d.test +++ b/test/tkt-2d1a5c67d.test @@ -118,8 +118,8 @@ do_test 3.5 { # forcedelete test.db2-wal test.db2 do_test 3.6 { - file copy test.db-wal test.db2-wal - file copy test.db test.db2 + copy_file test.db-wal test.db2-wal + copy_file test.db test.db2 sqlite3 db2 test.db2 execsql { SELECT * FROM t4 WHERE a = 'xyz' } db2 } {xyz} diff --git a/test/tkt-31338dca7e.test b/test/tkt-31338dca7e.test index 3f66816d..9423c684 100644 --- a/test/tkt-31338dca7e.test +++ b/test/tkt-31338dca7e.test @@ -74,4 +74,105 @@ do_test tkt-31338-2.2 { } {111 222 222 333 888 333 444 444 555 888 333 444 444 555 999} +# Ticket [2c2de252666662f5459904fc33a9f2956cbff23c] +# +do_test tkt-31338-3.1 { + foreach x [db eval {SELECT name FROM sqlite_master WHERE type='table'}] { + db eval "DROP TABLE $x" + } + db eval { + CREATE TABLE t1(a,b,c,d); + CREATE TABLE t2(e,f); + INSERT INTO t1 VALUES(1,2,3,4); + INSERT INTO t2 VALUES(10,-8); + CREATE INDEX t1a ON t1(a); + CREATE INDEX t1b ON t1(b); + CREATE TABLE t3(g); + INSERT INTO t3 VALUES(4); + CREATE TABLE t4(h); + INSERT INTO t4 VALUES(5); + + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} +do_test tkt-31338-3.2 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b=2 AND b NOT IN ( + SELECT x+1 FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} +do_test tkt-31338-3.3 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (+a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} +do_test tkt-31338-3.4 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (+b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 1 2 3 4 {}} + +do_test tkt-31338-3.5 { + db eval { + CREATE TABLE t5(a,b,c,d,e,f); + CREATE TABLE t6(g,h); + CREATE TRIGGER t6r AFTER INSERT ON t6 BEGIN + INSERT INTO t5 + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + END; + INSERT INTO t6 VALUES(88,99); + SELECT * FROM t5; + } +} {4 1 2 3 4 {}} + +do_test tkt-31338-3.6 { + db eval { + INSERT INTO t1 VALUES(2,4,3,4); + INSERT INTO t1 VALUES(99,101,3,4); + INSERT INTO t1 VALUES(98,97,3,4); + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x+a FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 2 4 3 4 {} 4 99 101 3 4 {}} + +do_test tkt-31338-3.7 { + db eval { + SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h + WHERE (a=1 AND h=4) + OR (b IN ( + SELECT x FROM (SELECT e+f+a AS x, e FROM t2 ORDER BY 1 LIMIT 2) + GROUP BY e + )); + } +} {4 2 4 3 4 {} 4 99 101 3 4 {}} + + finish_test diff --git a/test/tkt-54844eea3f.test b/test/tkt-54844eea3f.test new file mode 100644 index 00000000..7b04f693 --- /dev/null +++ b/test/tkt-54844eea3f.test @@ -0,0 +1,67 @@ +# 2011 July 8 +# +# 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 file is testing that bug [54844eea3f] has been fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +set ::testprefix tkt-54844eea3f + +do_test 1.0 { + execsql { + CREATE TABLE t1(a INTEGER PRIMARY KEY); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(4); + + CREATE TABLE t2(b INTEGER PRIMARY KEY); + INSERT INTO t2 VALUES(1); + INSERT INTO t2 VALUES(2); + INSERT INTO t2 SELECT b+2 FROM t2; + INSERT INTO t2 SELECT b+4 FROM t2; + INSERT INTO t2 SELECT b+8 FROM t2; + INSERT INTO t2 SELECT b+16 FROM t2; + + CREATE TABLE t3(c INTEGER PRIMARY KEY); + INSERT INTO t3 VALUES(1); + INSERT INTO t3 VALUES(2); + INSERT INTO t3 VALUES(3); + } +} {} + +do_test 1.1 { + execsql { + SELECT 'test-2', t3.c, ( + SELECT count(*) + FROM t1 JOIN (SELECT DISTINCT t3.c AS p FROM t2) AS x ON t1.a=x.p + ) + FROM t3; + } +} {test-2 1 1 test-2 2 0 test-2 3 0} + +do_test 1.2 { + execsql { + CREATE TABLE t4(a, b, c); + INSERT INTO t4 VALUES('a', 1, 'one'); + INSERT INTO t4 VALUES('a', 2, 'two'); + INSERT INTO t4 VALUES('b', 1, 'three'); + INSERT INTO t4 VALUES('b', 2, 'four'); + SELECT ( + SELECT c FROM ( + SELECT * FROM t4 WHERE a=out.a ORDER BY b LIMIT 10 OFFSET 1 + ) WHERE b=out.b + ) FROM t4 AS out; + } +} {{} two {} four} + + +finish_test diff --git a/test/tkt-5ee23731f.test b/test/tkt-5ee23731f.test index 61c99741..761382a4 100644 --- a/test/tkt-5ee23731f.test +++ b/test/tkt-5ee23731f.test @@ -19,7 +19,7 @@ source $testdir/tester.tcl do_test tkt-5ee237-1.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE t1(x UNIQUE); diff --git a/test/tkt-b1d3a2e531.test b/test/tkt-b1d3a2e531.test new file mode 100644 index 00000000..54534b6c --- /dev/null +++ b/test/tkt-b1d3a2e531.test @@ -0,0 +1,109 @@ +# 2011 August 22 +# +# 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. +# +# This file implements tests for foreign keys. Specifically, it tests +# that ticket b1d3a2e531 has been fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable {!foreignkey||!trigger} { + finish_test + return +} +set testprefix tkt-b1d3a2e531 + +do_execsql_test 1.0 { PRAGMA foreign_keys = ON } + +do_execsql_test 1.1 { + CREATE TABLE pp(x PRIMARY KEY); + CREATE TABLE cc(y REFERENCES pp DEFERRABLE INITIALLY DEFERRED); + INSERT INTO pp VALUES('abc'); + INSERT INTO cc VALUES('abc'); +} +do_execsql_test 1.2 { + BEGIN; + DROP TABLE pp; + DROP TABLE cc; + COMMIT; +} +do_execsql_test 1.3 { + CREATE TABLE pp(x PRIMARY KEY); + CREATE TABLE cc(y REFERENCES pp DEFERRABLE INITIALLY DEFERRED); + INSERT INTO pp VALUES('abc'); + INSERT INTO cc VALUES('abc'); +} +do_execsql_test 1.4 { + BEGIN; + DROP TABLE cc; + DROP TABLE pp; + COMMIT; +} + +do_execsql_test 2.1 { + CREATE TABLE pp(x PRIMARY KEY); + CREATE TABLE cc( + y INTEGER PRIMARY KEY REFERENCES pp DEFERRABLE INITIALLY DEFERRED + ); + INSERT INTO pp VALUES(5); + INSERT INTO cc VALUES(5); +} +do_execsql_test 2.2 { + BEGIN; + DROP TABLE pp; + DROP TABLE cc; + COMMIT; +} +do_execsql_test 2.3 { + CREATE TABLE pp(x PRIMARY KEY); + CREATE TABLE cc( + y INTEGER PRIMARY KEY REFERENCES pp DEFERRABLE INITIALLY DEFERRED + ); + INSERT INTO pp VALUES(5); + INSERT INTO cc VALUES(5); +} +do_execsql_test 2.4 { + BEGIN; + DROP TABLE cc; + DROP TABLE pp; + COMMIT; +} + +do_execsql_test 3.1 { + CREATE TABLE pp1(x PRIMARY KEY); + CREATE TABLE cc1(y REFERENCES pp1 DEFERRABLE INITIALLY DEFERRED); + + CREATE TABLE pp2(x PRIMARY KEY); + CREATE TABLE cc2(y REFERENCES pp1 DEFERRABLE INITIALLY DEFERRED); + + INSERT INTO pp1 VALUES(2200); + INSERT INTO cc1 VALUES(NULL); + + INSERT INTO pp2 VALUES(2200); + INSERT INTO cc2 VALUES(2200); +} +do_catchsql_test 3.2 { + BEGIN; + DELETE FROM pp2; + DROP TABLE pp1; + DROP TABLE cc1; + COMMIT; +} {1 {foreign key constraint failed}} +do_catchsql_test 3.3 { + DROP TABLE cc2; + COMMIT; +} {0 {}} + + + +finish_test diff --git a/test/tkt-c48d99d690.test b/test/tkt-c48d99d690.test new file mode 100644 index 00000000..9b405799 --- /dev/null +++ b/test/tkt-c48d99d690.test @@ -0,0 +1,26 @@ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +set ::testprefix tkt-c48d99d690 + +do_test 1.0 { + execsql { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); + INSERT INTO t1 VALUES('one' , 1); + INSERT INTO t1 VALUES('two' , 5); + INSERT INTO t1 VALUES('two' , 2); + INSERT INTO t1 VALUES('three', 3); + PRAGMA count_changes = 1; + } +} {} + +do_test 1.1 { + execsql { INSERT INTO t2 SELECT * FROM t1 } +} {4} + +do_test 1.2 { execsql VACUUM } {} + +finish_test + diff --git a/test/tkt-cbd054fa6b.test b/test/tkt-cbd054fa6b.test index 6e7455b3..180acf56 100644 --- a/test/tkt-cbd054fa6b.test +++ b/test/tkt-cbd054fa6b.test @@ -16,7 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !stat2 { +ifcapable !stat3 { finish_test return } @@ -46,7 +46,7 @@ do_test tkt-cbd05-1.2 { do_test tkt-cbd05-1.3 { execsql { SELECT tbl,idx,group_concat(sample,' ') - FROM sqlite_stat2 + FROM sqlite_stat3 WHERE idx = 't1_x' GROUP BY tbl,idx } @@ -78,7 +78,7 @@ do_test tkt-cbd05-2.2 { do_test tkt-cbd05-2.3 { execsql { SELECT tbl,idx,group_concat(sample,' ') - FROM sqlite_stat2 + FROM sqlite_stat3 WHERE idx = 't1_x' GROUP BY tbl,idx } diff --git a/test/tkt-d635236375.test b/test/tkt-d635236375.test new file mode 100644 index 00000000..3fc78226 --- /dev/null +++ b/test/tkt-d635236375.test @@ -0,0 +1,38 @@ +# 2011 August 3 +# +# 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 file is testing that bug [d63523637517386191d634e] +# has been fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +set ::testprefix tkt-d635236375 + +do_test 1.0 { + execsql { + CREATE TABLE t1(id1 INTEGER PRIMARY KEY); + INSERT INTO t1 VALUES(9999); + CREATE TABLE t2(id2 INTEGER PRIMARY KEY); + INSERT INTO t2 VALUES(12345); + INSERT INTO t2 VALUES(54321); + SELECT DISTINCT id1 AS x, id1 AS y FROM t1, t2; + } +} {9999 9999} +do_test 1.1 { + execsql { + SELECT count(*) FROM t1, t2 GROUP BY id1, id1; + } +} {2} + + +finish_test diff --git a/test/tkt-f3e5abed55.test b/test/tkt-f3e5abed55.test index 241c1612..b3f5d565 100644 --- a/test/tkt-f3e5abed55.test +++ b/test/tkt-f3e5abed55.test @@ -14,8 +14,8 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl -foreach f [glob -nocomplain test.db*mj*] { file delete -force $f } -file delete -force test.db2 +foreach f [glob -nocomplain test.db*mj*] { forcedelete $f } +forcedelete test.db2 do_test tkt-f3e5abed55-1.1 { execsql { @@ -51,7 +51,7 @@ do_test tkt-f3e5abed55-1.5 { do_test tkt-f3e5abed55-1.6 { glob -nocomplain test.db*mj* } {} -foreach f [glob -nocomplain test.db*mj*] { file delete -force $f } +foreach f [glob -nocomplain test.db*mj*] { forcedelete $f } db close db2 close diff --git a/test/tkt-fa7bf5ec.test b/test/tkt-fa7bf5ec.test new file mode 100644 index 00000000..34f12b96 --- /dev/null +++ b/test/tkt-fa7bf5ec.test @@ -0,0 +1,39 @@ +# 2011 October 13 +# +# 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. Specifically, +# it tests that ticket [fa7bf5ec94801e7e2030e41eefe5d9dd96eaacfd] has +# been resolved. +# +# The problem described by this ticket was that the sqlite3ExprCompare() +# function was saying that expressions (x='a') and (x='A') were identical +# because it was using sqlite3StrICmp() instead of strcmp() to compare string +# literals. That was causing the query optimizer for aggregate queries to +# believe that both count() operations were identical, and thus only +# computing the first count() and making a copy of the result for the +# second count(). +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_test tkt-fa7bf5ec-1 { + execsql { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES ('a'); + INSERT INTO t1 VALUES ('A'); + INSERT INTO t1 VALUES ('A'); + SELECT count(CASE WHEN x='a' THEN 1 END), + count(CASE WHEN x='A' THEN 1 END) + FROM t1; + } +} {1 2} + +finish_test diff --git a/test/tkt1667.test b/test/tkt1667.test index 9883a208..63815061 100644 --- a/test/tkt1667.test +++ b/test/tkt1667.test @@ -25,7 +25,7 @@ ifcapable !autovacuum||!tclvar { } db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal # Set the pending byte offset such that the page it is on is # the first autovacuum pointer map page in the file (assume a page diff --git a/test/tkt1873.test b/test/tkt1873.test index 85a52832..9930790c 100644 --- a/test/tkt1873.test +++ b/test/tkt1873.test @@ -24,7 +24,7 @@ ifcapable !attach { return } -file delete -force test2.db test2.db-journal +forcedelete test2.db test2.db-journal do_test tkt1873-1.1 { execsql { diff --git a/test/tkt2686.test b/test/tkt2686.test index c03c6868..20447bba 100644 --- a/test/tkt2686.test +++ b/test/tkt2686.test @@ -49,7 +49,7 @@ for {set i 1} {$i<2000} {incr i} { } db close -file delete -force test.db test.db-journal +forcedelete test.db test.db-journal sqlite3 db test.db db eval { diff --git a/test/tkt2817.test b/test/tkt2817.test index 46b7fe36..579cf2f7 100644 --- a/test/tkt2817.test +++ b/test/tkt2817.test @@ -48,7 +48,7 @@ integrity_check tkt2817-1.3 # same name. #2817 did not cause a problem with these tests. # db close -file delete -force test.db +forcedelete test.db sqlite3 db test.db do_test tkt2817-2.0 { execsql { diff --git a/test/tkt2820.test b/test/tkt2820.test index 106c1e55..11c4cd3a 100644 --- a/test/tkt2820.test +++ b/test/tkt2820.test @@ -25,7 +25,7 @@ source $testdir/tester.tcl proc test_schema_change {testid init ddl res} { db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db execsql $init do_test tkt2820-$testid.1 { @@ -70,7 +70,7 @@ test_schema_change 3 { # do_test tkt2820-4.1 { db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY); diff --git a/test/tkt2854.test b/test/tkt2854.test index 862524a7..914ddd1b 100644 --- a/test/tkt2854.test +++ b/test/tkt2854.test @@ -128,7 +128,7 @@ do_test tkt2854-1.18 { # attached db cannot be locked, the internal exclusive flag used by # shared-cache users is correctly cleared. do_test tkt2854-1.19 { - file delete -force test2.db test2.db-journal + forcedelete test2.db test2.db-journal sqlite3 db4 test2.db execsql { CREATE TABLE def(d, e, f) } db4 execsql { ATTACH 'test2.db' AS aux } db diff --git a/test/tkt3457.test b/test/tkt3457.test index 71eb4246..7b9a1b35 100644 --- a/test/tkt3457.test +++ b/test/tkt3457.test @@ -46,8 +46,8 @@ do_test tkt3457-1.1 { INSERT INTO t1 VALUES(4, 5, 6); } - file copy -force test.db bak.db - file copy -force test.db-journal bak.db-journal + forcecopy test.db bak.db + forcecopy test.db-journal bak.db-journal # Fix the first journal-header in the journal-file. Because the # journal file has not yet been synced, the 8-byte magic string at the @@ -63,23 +63,23 @@ do_test tkt3457-1.1 { } {} do_test tkt3457-1.2 { - file copy -force bak.db-journal test.db-journal + forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions --------- catchsql { SELECT * FROM t1 } } {1 {unable to open database file}} do_test tkt3457-1.3 { - file copy -force bak.db-journal test.db-journal + forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions -w--w--w- catchsql { SELECT * FROM t1 } } {1 {unable to open database file}} do_test tkt3457-1.4 { - file copy -force bak.db-journal test.db-journal + forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions r--r--r-- catchsql { SELECT * FROM t1 } } {1 {unable to open database file}} do_test tkt3457-1.5 { - file copy -force bak.db-journal test.db-journal + forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions rw-rw-rw- catchsql { SELECT * FROM t1 } } {0 {1 2 3 4 5 6}} diff --git a/test/tkt35xx.test b/test/tkt35xx.test index d2a83cde..f9d10c30 100644 --- a/test/tkt35xx.test +++ b/test/tkt35xx.test @@ -50,7 +50,7 @@ do_test tkt35xx-1.1 { # Trigger the problem using statement rollback. # db close -file delete test.db +delete_file test.db sqlite3 db test.db set big [string repeat abcdefghij 22] ;# 220 byte string do_test tkt35xx-1.2.1 { diff --git a/test/tkt3793.test b/test/tkt3793.test index 2b5f2bab..074aab2d 100644 --- a/test/tkt3793.test +++ b/test/tkt3793.test @@ -100,16 +100,18 @@ set x 0 # Note: Before the bug was fixed, if [db2] was opened with the "-fullmutex 1" # option, then this test case would cause an assert() to fail. # -set ::busyconnection db1 -db1 eval {SELECT * FROM t2 ORDER BY a LIMIT 20} { - do_test tkt3793-2.[incr x] { set ::busyconnection } db1 - set ::busyconnection db2 - - db2 eval { SELECT count(*) FROM t2 } - do_test tkt3793-2.[incr x] { set ::busyconnection } db2 +ifcapable threadsafe { set ::busyconnection db1 + db1 eval {SELECT * FROM t2 ORDER BY a LIMIT 20} { + do_test tkt3793-2.[incr x] { set ::busyconnection } db1 + set ::busyconnection db2 + + db2 eval { SELECT count(*) FROM t2 } + do_test tkt3793-2.[incr x] { set ::busyconnection } db2 + set ::busyconnection db1 + } } - + do_test tkt3793-3 { db1 close db2 close diff --git a/test/trigger1.test b/test/trigger1.test index 622aff2d..dc344d4d 100644 --- a/test/trigger1.test +++ b/test/trigger1.test @@ -534,8 +534,8 @@ ifcapable conflict { # example, that you can drop and re-create tables referenced by triggers. ifcapable tempdb&&attach { do_test trigger1-10.0 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { ATTACH 'test2.db' AS aux; } diff --git a/test/trigger4.test b/test/trigger4.test index 0e44ce6c..a05a5e73 100644 --- a/test/trigger4.test +++ b/test/trigger4.test @@ -130,8 +130,8 @@ do_test trigger4-3.7 { do_test trigger4-4.1 { db close - file delete -force trigtest.db - file delete -force trigtest.db-journal + forcedelete trigtest.db + forcedelete trigtest.db-journal sqlite3 db trigtest.db catchsql {drop table tbl; drop view vw} execsql { @@ -195,6 +195,6 @@ do_test trigger4-7.2 { integrity_check trigger4-99.9 db close -file delete -force trigtest.db trigtest.db-journal +forcedelete trigtest.db trigtest.db-journal finish_test diff --git a/test/triggerA.test b/test/triggerA.test index 9f93db5c..0bc017ff 100644 --- a/test/triggerA.test +++ b/test/triggerA.test @@ -205,16 +205,16 @@ source $testdir/malloc_common.tcl # Save a copy of the current database configuration. # db close -file delete -force test.db-triggerA -file copy test.db test.db-triggerA +forcedelete test.db-triggerA +copy_file test.db test.db-triggerA sqlite3 db test.db # Run malloc tests on the INSTEAD OF trigger firing. # do_malloc_test triggerA-3 -tclprep { db close - file delete -force test.db test.db-journal - file copy -force test.db-triggerA test.db + forcedelete test.db test.db-journal + forcecopy test.db-triggerA test.db sqlite3 db test.db sqlite3_extended_result_codes db 1 db eval {SELECT * FROM v5; -- warm up the cache} @@ -225,6 +225,6 @@ do_malloc_test triggerA-3 -tclprep { # Clean up the saved database copy. # -file delete -force test.db-triggerA +forcedelete test.db-triggerA finish_test diff --git a/test/triggerC.test b/test/triggerC.test index e5a492a4..12a5e4ac 100644 --- a/test/triggerC.test +++ b/test/triggerC.test @@ -918,7 +918,7 @@ do_test triggerC-11.4 { do_test triggerC-12.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { diff --git a/test/triggerD.test b/test/triggerD.test index 08945081..a5dd4bdd 100644 --- a/test/triggerD.test +++ b/test/triggerD.test @@ -14,6 +14,12 @@ # the use of these columns in triggers will refer to the column and not # to the actual ROWID. Ticket [34d2ae1c6d08b5271ba5e5592936d4a1d913ffe3] # +# Also, verify that triggers created like this: +# +# CREATE TRIGGER attached.trig AFTER INSERT ON attached.tab ... +# +# can be reparsed as a main database. Ticket [d6ddba6706353915ceedc56b4e3] +# set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -171,4 +177,43 @@ do_test triggerD-3.2 { } {10003 20004} +############################################################################# +# +# Ticket [d6ddba6706353915ceedc56b4e3e72ecb4d77ba4] +# +# The following syntax really should not be allowed: +# +# CREATE TRIGGER xyz.trig BEFORE UPDATE ON xyz.tab BEGIN ... +# +# But a long-standing bug does allow it. And the "xyz.tab" slips into +# the sqlite_master table. We cannot fix the bug simply by disallowing +# "xyz.tab" since that could break legacy applications. We have to +# fix the system so that the "xyz." on "xyz.tab" is ignored. +# Verify that this is the case. +# +do_test triggerD-4.1 { + db close + forcedelete test.db test2.db + sqlite3 db test.db + db eval { + CREATE TABLE t1(x); + ATTACH 'test2.db' AS db2; + CREATE TABLE db2.t2(y); + CREATE TABLE db2.log(z); + CREATE TRIGGER db2.trig AFTER INSERT ON db2.t2 BEGIN + INSERT INTO log(z) VALUES(new.y); + END; + INSERT INTO t2 VALUES(123); + SELECT * FROM log; + } +} {123} +do_test triggerD-4.2 { + sqlite3 db2 test2.db + db2 eval { + INSERT INTO t2 VALUES(234); + SELECT * FROM log; + } +} {123 234} +db2 close + finish_test diff --git a/test/unordered.test b/test/unordered.test index a9c62534..6c7c2bb2 100644 --- a/test/unordered.test +++ b/test/unordered.test @@ -31,11 +31,13 @@ do_execsql_test 1.0 { } {} foreach idxmode {ordered unordered} { + catchsql { DELETE FROM sqlite_stat2 } + catchsql { DELETE FROM sqlite_stat3 } if {$idxmode == "unordered"} { execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' } - db close - sqlite3 db test.db } + db close + sqlite3 db test.db foreach {tn sql r(ordered) r(unordered)} { 1 "SELECT * FROM t1 ORDER BY a" {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}} diff --git a/test/uri.test b/test/uri.test index f361e929..90074d0d 100644 --- a/test/uri.test +++ b/test/uri.test @@ -219,44 +219,46 @@ do_test 4.3.2 { # set, where X is the file-name the method is called on. Calls to the above # methods using "tvfs2" set entries in the global T2 array. # -testvfs tvfs1 -tvfs1 filter {xOpen xDelete xAccess xFullPathname} -tvfs1 script tvfs1_callback -proc tvfs1_callback {method filename args} { - set ::T1([file tail $filename]) 1 -} -testvfs tvfs2 -tvfs2 filter {xOpen xDelete xAccess xFullPathname} -tvfs2 script tvfs2_callback -proc tvfs2_callback {method filename args} { - set ::T2([file tail $filename]) 1 -} - -catch {db close} -eval forcedelete [glob test.db*] -do_test 5.1.1 { - sqlite3 db file:test.db1?vfs=tvfs1 - execsql { - ATTACH 'file:test.db2?vfs=tvfs2' AS aux; - PRAGMA main.journal_mode = PERSIST; - PRAGMA aux.journal_mode = PERSIST; - CREATE TABLE t1(a, b); - CREATE TABLE aux.t2(a, b); - PRAGMA main.journal_mode = WAL; - PRAGMA aux.journal_mode = WAL; - INSERT INTO t1 VALUES('x', 'y'); - INSERT INTO t2 VALUES('x', 'y'); +ifcapable wal { + testvfs tvfs1 + tvfs1 filter {xOpen xDelete xAccess xFullPathname} + tvfs1 script tvfs1_callback + proc tvfs1_callback {method filename args} { + set ::T1([file tail $filename]) 1 } - lsort [array names ::T1] -} {test.db1 test.db1-journal test.db1-wal} - -do_test 5.1.2 { - lsort [array names ::T2] -} {test.db2 test.db2-journal test.db2-wal} - -db close -tvfs1 delete -tvfs2 delete + testvfs tvfs2 + tvfs2 filter {xOpen xDelete xAccess xFullPathname} + tvfs2 script tvfs2_callback + proc tvfs2_callback {method filename args} { + set ::T2([file tail $filename]) 1 + } + + catch {db close} + eval forcedelete [glob test.db*] + do_test 5.1.1 { + sqlite3 db file:test.db1?vfs=tvfs1 + execsql { + ATTACH 'file:test.db2?vfs=tvfs2' AS aux; + PRAGMA main.journal_mode = PERSIST; + PRAGMA aux.journal_mode = PERSIST; + CREATE TABLE t1(a, b); + CREATE TABLE aux.t2(a, b); + PRAGMA main.journal_mode = WAL; + PRAGMA aux.journal_mode = WAL; + INSERT INTO t1 VALUES('x', 'y'); + INSERT INTO t2 VALUES('x', 'y'); + } + lsort [array names ::T1] + } {test.db1 test.db1-journal test.db1-wal} + + do_test 5.1.2 { + lsort [array names ::T2] + } {test.db2 test.db2-journal test.db2-wal} + db close + + tvfs1 delete + tvfs2 delete +} #------------------------------------------------------------------------- # Check that only "" and "localhost" are acceptable as authorities. diff --git a/test/vacuum.test b/test/vacuum.test index 34be57ce..57429c29 100644 --- a/test/vacuum.test +++ b/test/vacuum.test @@ -208,7 +208,7 @@ db3 close do_test vacuum-3.1 { db close db2 close - file delete test.db + delete_file test.db sqlite3 db test.db execsql { PRAGMA empty_result_callbacks=on; @@ -234,7 +234,7 @@ do_test vacuum-4.2 { ifcapable view { do_test vacuum-5.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db catchsql { CREATE TABLE Test (TestID int primary key); @@ -290,10 +290,10 @@ ifcapable {bloblit} { } # Check what happens when an in-memory database is vacuumed. The -# [file delete] command covers us in case the library was compiled +# [delete_file] command covers us in case the library was compiled # without in-memory database support. # -file delete -force :memory: +forcedelete :memory: do_test vacuum-7.0 { sqlite3 db2 :memory: execsql { @@ -337,8 +337,8 @@ db2 close # Ticket #873. VACUUM a database that has ' in its name. # do_test vacuum-8.1 { - file delete -force a'z.db - file delete -force a'z.db-journal + forcedelete a'z.db + forcedelete a'z.db-journal sqlite3 db2 a'z.db execsql { CREATE TABLE t1(t); @@ -383,6 +383,22 @@ ifcapable {autoinc} { } $::cksum } -file delete -force {a'z.db} +forcedelete {a'z.db} + +# Test that "PRAGMA count_changes" does not interfere with VACUUM or cause +# it to return any rows to the user. +# +do_test vacuum-10.1 { + db close + forcedelete test.db + sqlite3 db test.db + execsql { + CREATE TABLE t8(a, b); + INSERT INTO t8 VALUES('a', 'b'); + INSERT INTO t8 VALUES('c', 'd'); + PRAGMA count_changes = 1; + } +} {} +do_test vacuum-10.2 { execsql VACUUM } {} finish_test diff --git a/test/vacuum2.test b/test/vacuum2.test index 35524bb2..b3bfab30 100644 --- a/test/vacuum2.test +++ b/test/vacuum2.test @@ -135,7 +135,7 @@ db2 close ifcapable autovacuum { do_test vacuum2-4.1 { db close - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { pragma auto_vacuum=1; diff --git a/test/vacuum3.test b/test/vacuum3.test index f6b75d70..484a7d44 100644 --- a/test/vacuum3.test +++ b/test/vacuum3.test @@ -196,7 +196,7 @@ foreach {request actual} [list \ do_test vacuum3-4.1 { db close - file delete test.db + delete_file test.db sqlite3 db test.db execsql { PRAGMA page_size=1024; diff --git a/test/view.test b/test/view.test index a87d2770..b4440905 100644 --- a/test/view.test +++ b/test/view.test @@ -458,7 +458,7 @@ do_test view-12.1 { ifcapable attach { do_test view-13.1 { - file delete -force test2.db + forcedelete test2.db catchsql { ATTACH 'test2.db' AS two; CREATE TABLE two.t2(x,y); diff --git a/test/vtab1.test b/test/vtab1.test index a9aca503..16f1b438 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -724,8 +724,8 @@ do_test vtab1-6-8.4 { } {} execsql {PRAGMA count_changes=OFF} -file delete -force test2.db -file delete -force test2.db-journal +forcedelete test2.db +forcedelete test2.db-journal sqlite3 db2 test2.db execsql { CREATE TABLE techo(a PRIMARY KEY, b, c); @@ -1178,5 +1178,20 @@ do_test vtab1-17.1 { catchsql { CREATE VIRTUAL TABLE t4 USING echo(t3); } } {1 {vtable constructor failed: t4}} +# This test verifies that ticket 48f29963 is fixed. +# +do_test vtab1-17.1 { + execsql { + CREATE TABLE t5(a, b); + CREATE VIRTUAL TABLE e5 USING echo_v2(t5); + BEGIN; + INSERT INTO e5 VALUES(1, 2); + DROP TABLE e5; + SAVEPOINT one; + ROLLBACK TO one; + COMMIT; + } +} {} + unset -nocomplain echo_module_begin_fail finish_test diff --git a/test/vtab7.test b/test/vtab7.test index d1b1f590..162bab5e 100644 --- a/test/vtab7.test +++ b/test/vtab7.test @@ -134,8 +134,8 @@ execsql {DROP TABLE newtab} # Write to an attached database from xSync(). ifcapable attach { do_test vtab7-3.1 { - file delete -force test2.db - file delete -force test2.db-journal + forcedelete test2.db + forcedelete test2.db-journal execsql { ATTACH 'test2.db' AS db2; CREATE TABLE db2.stuff(description, shape, color); diff --git a/test/vtabC.test b/test/vtabC.test index 824d4ca2..ca78b706 100644 --- a/test/vtabC.test +++ b/test/vtabC.test @@ -31,7 +31,7 @@ ifcapable !trigger { finish_test ; return } unset -nocomplain N for {set N 1} {$N<=20} {incr N} { db close - file delete -force test.db test.db-journal + forcedelete test.db test.db-journal sqlite3 db test.db register_echo_module [sqlite3_connection_pointer db] diff --git a/test/vtabF.test b/test/vtabF.test new file mode 100644 index 00000000..b9341ea5 --- /dev/null +++ b/test/vtabF.test @@ -0,0 +1,45 @@ +# 2011 Aug 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 file implements regression tests for SQLite library. +# This file checks to make sure IS NOT NULL constraints work on +# virtual tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !vtab||!schema_pragmas { finish_test ; return } + +# Register the echo module +register_echo_module [sqlite3_connection_pointer db] + +do_test vtabE-1.1 { + execsql { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); + CREATE INDEX i2 ON t1(b); + INSERT INTO t1 VALUES(10,110); + INSERT INTO t1 VALUES(11,111); + INSERT INTO t1 SELECT a+2, b+2 FROM t1; + INSERT INTO t1 SELECT null, b+4 FROM t1; + INSERT INTO t1 SELECT null, b+8 FROM t1; + INSERT INTO t1 SELECT null, b+16 FROM t1; + ANALYZE; + CREATE VIRTUAL TABLE tv1 USING echo(t1); + SELECT b FROM t1 WHERE a IS NOT NULL; + } +} {110 111 112 113} +do_test vtabE-1.2 { + execsql {SELECT b FROM tv1 WHERE a IS NOT NULL} +} {110 111 112 113} + + +finish_test diff --git a/test/wal.test b/test/wal.test index 1aa70e05..056becf7 100644 --- a/test/wal.test +++ b/test/wal.test @@ -25,7 +25,7 @@ ifcapable !wal {finish_test ; return } proc reopen_db {} { catch { db close } - file delete -force test.db test.db-wal test.db-wal-summary + forcedelete test.db test.db-wal test.db-wal-summary sqlite3_wal db test.db } @@ -211,8 +211,8 @@ do_test wal-4.4.5 { execsql { SELECT count(*) FROM t2 } } {1} do_test wal-4.4.6 { - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal sqlite3 db2 test2.db execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2 } {1 2} @@ -269,8 +269,8 @@ do_test wal-4.5.5 { execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } } {1 2} do_test wal-4.5.6 { - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal sqlite3 db2 test2.db execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2 } {1 2} @@ -334,7 +334,7 @@ db close foreach sector {512 4096} { sqlite3_simulate_device -sectorsize $sector foreach pgsz {512 1024 2048 4096} { - file delete -force test.db test.db-wal + forcedelete test.db test.db-wal do_test wal-6.$sector.$pgsz.1 { sqlite3 db test.db -vfs devsym execsql " @@ -357,7 +357,7 @@ foreach sector {512 4096} { } do_test wal-7.1 { - file delete -force test.db test.db-wal + forcedelete test.db test.db-wal sqlite3_wal db test.db execsql { PRAGMA page_size = 1024; @@ -377,7 +377,7 @@ do_test wal-7.2 { do_test wal-8.1 { reopen_db catch { db close } - file delete -force test.db test.db-wal + forcedelete test.db test.db-wal sqlite3 db test.db db function blob blob @@ -435,9 +435,9 @@ do_test wal-9.2 { } {ok} do_test wal-9.3 { - file delete -force test2.db test2.db-wal - file copy test.db test2.db - file copy test.db-wal test2.db-wal + forcedelete test2.db test2.db-wal + copy_file test.db test2.db + copy_file test.db-wal test2.db-wal sqlite3_wal db3 test2.db execsql {PRAGMA integrity_check } db3 } {ok} @@ -786,8 +786,8 @@ do_test wal-12.3 { list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044] } {3 2} do_test wal-12.4 { - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal sqlite3_wal db2 test2.db execsql { SELECT * FROM t2 } db2 } {B 1} @@ -804,8 +804,8 @@ do_test wal-12.5 { execsql { SELECT * FROM t2 } } {B 2} do_test wal-12.6 { - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal sqlite3_wal db2 test2.db execsql { SELECT * FROM t2 } db2 } {B 2} @@ -909,7 +909,7 @@ do_multiclient_test tn { catch { db close } catch { db2 close } catch { db3 close } -file delete -force test.db test.db-wal +forcedelete test.db test.db-wal sqlite3 db test.db sqlite3 db2 test.db do_test wal-14 { @@ -947,7 +947,7 @@ catch { db2 close } # The following block of tests - wal-15.* - focus on testing the # implementation of the sqlite3_wal_checkpoint() interface. # -file delete -force test.db test.db-wal +forcedelete test.db test.db-wal sqlite3 db test.db do_test wal-15.1 { execsql { @@ -1043,8 +1043,8 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} { 9 {db eval "PRAGMA temp.wal_checkpoint"} {0 -1 -1} 0 0 } { do_test wal-16.$tn.1 { - file delete -force test2.db test2.db-wal test2.db-journal - file delete -force test.db test.db-wal test.db-journal + forcedelete test2.db test2.db-wal test2.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { @@ -1116,7 +1116,7 @@ foreach {tn sectorsize logsize} " 6 4096 [wal_file_size 176 512] 7 8192 [wal_file_size 184 512] " { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3_simulate_device -sectorsize $sectorsize sqlite3 db test.db -vfs devsym @@ -1160,7 +1160,7 @@ sqlite3_test_control_pending_byte $old_pending_byte # wal-18.2.* When the page-size field that occurs at the start of a log # file is a power of 2 greater than 16384 or smaller than 512. # -file delete -force test.db test.db-wal test.db-journal +forcedelete test.db test.db-wal test.db-journal do_test wal-18.0 { sqlite3 db test.db execsql { @@ -1178,8 +1178,8 @@ do_test wal-18.0 { INSERT INTO t1 VALUES(5, 6); -- frames 5 and 6 } - file copy -force test.db testX.db - file copy -force test.db-wal testX.db-wal + forcecopy test.db testX.db + forcecopy test.db-wal testX.db-wal db close list [file size testX.db] [file size testX.db-wal] } [list [expr 3*1024] [wal_file_size 6 1024]] @@ -1195,8 +1195,8 @@ foreach {nFrame result} { 6 {0 0 1 2 3 4 5 6} } { do_test wal-18.1.$nFrame { - file copy -force testX.db test.db - file copy -force testX.db-wal test.db-wal + forcecopy testX.db test.db + forcecopy testX.db-wal test.db-wal hexio_write test.db-wal [expr 24 + $nFrame*(24+1024) + 20] 00000000 @@ -1232,7 +1232,7 @@ proc logcksum {ckv1 ckv2 blob} { } } -file copy -force test.db testX.db +forcecopy test.db testX.db foreach {tn pgsz works} { 1 128 0 2 256 0 @@ -1253,8 +1253,8 @@ foreach {tn pgsz works} { } for {set pg 1} {$pg <= 3} {incr pg} { - file copy -force testX.db test.db - file delete -force test.db-wal + forcecopy testX.db test.db + forcedelete test.db-wal # Check that the database now exists and consists of three pages. And # that there is no associated wal file. @@ -1321,7 +1321,7 @@ foreach {tn pgsz works} { # snapshot. # do_test wal-19.1 { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db sqlite3 db2 test.db execsql { @@ -1370,7 +1370,7 @@ do_test wal-19.4 { # do_test wal-20.1 { catch {db close} - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { PRAGMA journal_mode = WAL; @@ -1476,7 +1476,7 @@ foreach pgsz {512 1024 2048 4096 8192 16384 32768 65536} { # set walfile [file nativename [file join [pwd] test.db-wal]] catch {db close} -file delete -force test.db +forcedelete test.db do_test wal-23.1 { faultsim_delete_and_reopen execsql { diff --git a/test/wal2.test b/test/wal2.test index 97966cd9..f4887065 100644 --- a/test/wal2.test +++ b/test/wal2.test @@ -164,7 +164,7 @@ foreach {tn iInsert res wal_index_hdr_mod wal_locks} " db close db2 close tvfs delete -file delete -force test.db test.db-wal test.db-journal +forcedelete test.db test.db-wal test.db-journal #------------------------------------------------------------------------- # This test case is very similar to the previous one, except, after @@ -271,7 +271,7 @@ foreach {tn iInsert res0 res1 wal_index_hdr_mod} { db close db2 close tvfs delete -file delete -force test.db test.db-wal test.db-journal +forcedelete test.db test.db-wal test.db-journal if 0 { @@ -344,7 +344,7 @@ do_test wal2-3.5 { } {0 0} db close tvfs delete -file delete -force test.db test.db-wal test.db-journal +forcedelete test.db test.db-wal test.db-journal } @@ -441,7 +441,7 @@ tvfs delete # connection silently remains in exclusive mode. # do_test wal2-6.1.1 { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { Pragma Journal_Mode = Wal; @@ -484,7 +484,7 @@ do_test wal2-6.1.6 { db close do_test wal2-6.2.1 { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { Pragma Locking_Mode = Exclusive; @@ -552,7 +552,7 @@ do_test wal2-6.2.9 { db close do_test wal2-6.3.1 { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { PRAGMA journal_mode = WAL; @@ -597,7 +597,7 @@ db close # as expected when a WAL database is used with locking_mode=exclusive. # do_test wal2-6.4.1 { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal proc tvfs_cb {method args} { set ::shm_file [lindex $args 0] if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] } @@ -606,6 +606,7 @@ do_test wal2-6.4.1 { testvfs tvfs tvfs script tvfs_cb sqlite3 db test.db -vfs tvfs + set {} {} } {} set RECOVERY { @@ -792,7 +793,7 @@ T delete # Test a theory about the checksum algorithm. Theory was false and this # test did not provoke a bug. # -file delete -force test.db test.db-wal test.db-journal +forcedelete test.db test.db-wal test.db-journal do_test wal2-7.1.1 { sqlite3 db test.db execsql { @@ -803,8 +804,8 @@ do_test wal2-7.1.1 { file size test.db } {4096} do_test wal2-7.1.2 { - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal hexio_write test2.db-wal 48 FF } {1} do_test wal2-7.1.3 { @@ -814,7 +815,7 @@ do_test wal2-7.1.3 { } {} db close db2 close -file delete -force test.db test.db-wal test.db-journal +forcedelete test.db test.db-wal test.db-journal do_test wal2-8.1.2 { sqlite3 db test.db execsql { @@ -870,7 +871,7 @@ testvfs tvfs tvfs script get_name tvfs filter xShmOpen -file delete -force test.db test.db-wal test.db-journal +forcedelete test.db test.db-wal test.db-journal do_test wal2-9.1 { sqlite3 db test.db -vfs tvfs execsql { diff --git a/test/wal3.test b/test/wal3.test index bd296154..ea5e7057 100644 --- a/test/wal3.test +++ b/test/wal3.test @@ -94,9 +94,9 @@ for {set i 1} {$i < 50} {incr i} { # Check that the file-system in its current state can be recovered. # - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal - file delete -force test2.db-journal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal + forcedelete test2.db-journal sqlite3 db2 test2.db do_test wal3-1.$i.5 { execsql { SELECT count(*) FROM t1 } db2 @@ -208,7 +208,7 @@ foreach {tn syncmode synccount} { lappend ::syncs [file tail $filename] $flags } do_test wal3-3.$tn { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal testvfs T T filter {} @@ -411,7 +411,7 @@ T delete catch {db close} testvfs T -default 1 do_test wal3-6.1.1 { - file delete -force test.db test.db-journal test.db wal + forcedelete test.db test.db-journal test.db wal sqlite3 db test.db execsql { PRAGMA auto_vacuum = off } execsql { PRAGMA journal_mode = WAL } @@ -492,7 +492,7 @@ db2 close db close do_test wal3-6.2.1 { - file delete -force test.db test.db-journal test.db wal + forcedelete test.db test.db-journal test.db wal sqlite3 db test.db sqlite3 db2 test.db execsql { PRAGMA auto_vacuum = off } @@ -558,7 +558,7 @@ T delete catch {db close} testvfs T -default 1 do_test wal3-7.1.1 { - file delete -force test.db test.db-journal test.db wal + forcedelete test.db test.db-journal test.db wal sqlite3 db test.db execsql { PRAGMA journal_mode = WAL; @@ -615,7 +615,7 @@ T delete #------------------------------------------------------------------------- # do_test wal3-8.1 { - file delete -force test.db test.db-journal test.db wal + forcedelete test.db test.db-journal test.db wal sqlite3 db test.db sqlite3 db2 test.db execsql { @@ -707,9 +707,9 @@ T delete # and continues. # set nConn 50 -if { [string match *BSD $tcl_platform(os)] } { set nConn 35 } +if { [string match *BSD $tcl_platform(os)] } { set nConn 25 } do_test wal3-9.0 { - file delete -force test.db test.db-journal test.db wal + forcedelete test.db test.db-journal test.db wal sqlite3 db test.db execsql { PRAGMA page_size = 1024; @@ -784,4 +784,3 @@ do_multiclient_test tn { } finish_test - diff --git a/test/wal4.test b/test/wal4.test index 22ccfea7..c7a43813 100644 --- a/test/wal4.test +++ b/test/wal4.test @@ -31,7 +31,7 @@ do_test wal4-1.2 { # Save a copy of the file-system containing the wal and wal-index files # only (no database file). faultsim_save_and_close - file delete -force sv_test.db + forcedelete sv_test.db } {} do_test wal4-1.3 { diff --git a/test/wal5.test b/test/wal5.test index 0c700dfc..ad6bcfc7 100644 --- a/test/wal5.test +++ b/test/wal5.test @@ -235,14 +235,7 @@ foreach {testprefix do_wal_checkpoint} { do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {} do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7} do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 7 5} - if {$tcl_platform(platform) == "windows"} { - # on unix, the size_hint is a no-op if no chunk size is set. - # the windows implementation does not have a similar check, - # and because of this, the db file size has an extra page. - do_test 2.3.$tn.8 { file_page_counts } {2 7 2 7} - } { - do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7} - } + do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7} } # Check that checkpoints block on the correct locks. And respond correctly diff --git a/test/wal6.test b/test/wal6.test index 6fae48e9..ec31bb8b 100644 --- a/test/wal6.test +++ b/test/wal6.test @@ -43,19 +43,11 @@ foreach jmode $all_journal_modes { } {1 2} # Under Windows, you'll get an error trying to delete -# a file this is already opened. For now, make sure -# we get that error, then close the first connection +# a file this is already opened. Close the first connection # so the other tests work. if {$tcl_platform(platform)=="windows"} { if {$jmode=="persist" || $jmode=="truncate"} { - do_test wal6-1.2.$jmode.win { - sqlite3 db2 test.db - catchsql { - PRAGMA journal_mode=WAL; - } db2 - } {1 {disk I/O error}} - db2 close - db close + db close } } @@ -87,4 +79,3 @@ if {$tcl_platform(platform)=="windows"} { } finish_test - diff --git a/test/walbak.test b/test/walbak.test index fe5b99e1..303a628a 100644 --- a/test/walbak.test +++ b/test/walbak.test @@ -48,7 +48,7 @@ do_test walbak-1.0 { } } {wal} do_test walbak-1.1 { - file delete -force bak.db bak.db-journal bak.db-wal + forcedelete bak.db bak.db-journal bak.db-wal db backup bak.db file size bak.db } [expr 3*1024] @@ -79,6 +79,9 @@ do_test walbak-1.6 { execsql { PRAGMA wal_checkpoint } list [file size test.db] [file size test.db-wal] } [list [expr 3*1024] [wal_file_size 6 1024]] +do_test walbak-1.6.1 { + hexio_read test.db 18 2 +} {0202} do_test walbak-1.7 { execsql { CREATE TABLE t2(a, b); @@ -106,7 +109,7 @@ proc sig {{db db}} { } } db close -file delete test.db +delete_file test.db sqlite3 db test.db do_test walbak-2.1 { execsql { PRAGMA journal_mode = WAL } @@ -236,7 +239,7 @@ foreach {tn setup} { } } { - foreach f [glob -nocomplain test.db*] { file delete -force $f } + foreach f [glob -nocomplain test.db*] { forcedelete $f } eval $setup @@ -271,9 +274,84 @@ foreach {tn setup} { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6 7 8} + # Check that [db] is still in WAL mode. + do_test walbak-3.$tn.5 { + execsql { PRAGMA journal_mode } + } {wal} + do_test walbak-3.$tn.6 { + execsql { PRAGMA wal_checkpoint } + hexio_read test.db 18 2 + } {0202} + + # If it was not an in-memory database, check that [db2] is still in + # rollback mode. + if {[file exists test.db2]} { + do_test walbak-3.$tn.7 { + execsql { PRAGMA journal_mode } db2 + } {wal} + do_test walbak-3.$tn.8 { + execsql { PRAGMA wal_checkpoint } + hexio_read test.db 18 2 + } {0202} + } + db close db2 close } +#------------------------------------------------------------------------- +# Test that the following holds when a backup operation is run: +# +# Source | Destination inital | Destination final +# --------------------------------------------------- +# Rollback Rollback Rollback +# Rollback WAL WAL +# WAL Rollback WAL +# WAL WAL WAL +# +foreach {tn src dest dest_final} { + 1 delete delete delete + 2 delete wal wal + 3 wal delete wal + 4 wal wal wal +} { + catch { db close } + catch { db2 close } + forcedelete test.db test.db2 + + do_test walbak-4.$tn.1 { + sqlite3 db test.db + db eval "PRAGMA journal_mode = $src" + db eval { + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES('I', 'II'); + INSERT INTO t1 VALUES('III', 'IV'); + } + + sqlite3 db2 test.db2 + db2 eval "PRAGMA journal_mode = $dest" + db2 eval { + CREATE TABLE t2(x, y); + INSERT INTO t2 VALUES('1', '2'); + INSERT INTO t2 VALUES('3', '4'); + } + } {} + + do_test walbak-4.$tn.2 { execsql { PRAGMA journal_mode } db } $src + do_test walbak-4.$tn.3 { execsql { PRAGMA journal_mode } db2 } $dest + + do_test walbak-4.$tn.4 { db backup test.db2 } {} + do_test walbak-4.$tn.5 { + execsql { SELECT * FROM t1 } db2 + } {I II III IV} + do_test walbak-4.$tn.5 { execsql { PRAGMA journal_mode } db2 } $dest_final + + + db2 close + do_test walbak-4.$tn.6 { file exists test.db2-wal } 0 + sqlite3 db2 test.db2 + do_test walbak-4.$tn.7 { execsql { PRAGMA journal_mode } db2 } $dest_final +} + finish_test diff --git a/test/walbig.test b/test/walbig.test index 9ceb8ede..092db238 100644 --- a/test/walbig.test +++ b/test/walbig.test @@ -17,6 +17,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +ifcapable !wal { + finish_test + return +} + # Do not use a codec for this file, as the database is manipulated using # external methods (the [fake_big_file] and [hexio_write] commands). # diff --git a/test/walcksum.test b/test/walcksum.test index b2c4a905..08278dd0 100644 --- a/test/walcksum.test +++ b/test/walcksum.test @@ -153,7 +153,7 @@ foreach endian {big little} { # do_test walcksum-1.$endian.1 { catch { db close } - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { PRAGMA page_size = 1024; @@ -172,8 +172,8 @@ foreach endian {big little} { INSERT INTO t1 VALUES(21, 'twentyone'); } - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal db close list [file size test2.db] [file size test2.db-wal] @@ -199,8 +199,8 @@ foreach endian {big little} { } {1} } do_test walcksum-1.$endian.4.1 { - file copy -force test2.db test.db - file copy -force test2.db-wal test.db-wal + forcecopy test2.db test.db + forcecopy test2.db-wal test.db-wal sqlite3 db test.db execsql { SELECT a FROM t1 } } {1 2 3 5 8 13 21} @@ -248,8 +248,8 @@ foreach endian {big little} { # Now that both the recoverer and non-recoverer have added frames to the # log file, check that it can still be recovered. # - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal do_test walcksum-1.$endian.7.11 { sqlite3 db3 test2.db execsql { @@ -294,7 +294,7 @@ foreach endian {big little} { # formatted (and can be recovered by a second process if required). # do_test walcksum-2.1 { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { PRAGMA synchronous = NORMAL; @@ -322,8 +322,8 @@ do_test walcksum-2.1 { COMMIT; } - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal sqlite3 db2 test2.db execsql { @@ -340,7 +340,7 @@ catch { db2 close } # invalid as a result. # do_test walcksum-3.1 { - file delete -force test.db test.db-wal test.db-journal + forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { @@ -356,13 +356,13 @@ do_test walcksum-3.1 { file size test.db-wal } [wal_file_size 1 1024] do_test walcksum-3.2 { - file copy -force test.db-wal test2.db-wal - file copy -force test.db test2.db + forcecopy test.db-wal test2.db-wal + forcecopy test.db test2.db sqlite3 db2 test2.db execsql { SELECT a FROM t1 } db2 } {1 2 3} db2 close -file copy -force test.db test2.db +forcecopy test.db test2.db foreach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} { @@ -370,7 +370,7 @@ foreach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} { set FAIL 0 for {set iOff 0} {$iOff < [wal_file_size 1 1024]} {incr iOff} { - file copy -force test.db-wal test2.db-wal + forcecopy test.db-wal test2.db-wal set fd [open test2.db-wal r+] fconfigure $fd -encoding binary fconfigure $fd -translation binary diff --git a/test/walcrash.test b/test/walcrash.test index 0ef21fff..cfce5fed 100644 --- a/test/walcrash.test +++ b/test/walcrash.test @@ -37,7 +37,7 @@ set REPEATS 100 # walcrash-1.* # for {set i 1} {$i < $REPEATS} {incr i} { - file delete -force test.db test.db-wal + forcedelete test.db test.db-wal do_test walcrash-1.$i.1 { crashsql -delay 4 -file test.db-wal -seed [incr seed] { PRAGMA journal_mode = WAL; @@ -74,7 +74,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { # walcrash-2.* # for {set i 1} {$i < $REPEATS} {incr i} { - file delete -force test.db test.db-wal + forcedelete test.db test.db-wal do_test walcrash-2.$i.1 { crashsql -delay 4 -file test.db-wal -seed [incr seed] { PRAGMA journal_mode = WAL; @@ -111,8 +111,8 @@ for {set i 1} {$i < $REPEATS} {incr i} { # walcrash-3.* # # for {set i 1} {$i < $REPEATS} {incr i} { -# file delete -force test.db test.db-wal -# file delete -force test2.db test2.db-wal +# forcedelete test.db test.db-wal +# forcedelete test2.db test2.db-wal # # do_test walcrash-3.$i.1 { # crashsql -delay 2 -file test2.db-wal -seed [incr seed] { @@ -143,8 +143,8 @@ for {set i 1} {$i < $REPEATS} {incr i} { # walcrash-4.* # for {set i 1} {$i < $REPEATS} {incr i} { - file delete -force test.db test.db-wal - file delete -force test2.db test2.db-wal + forcedelete test.db test.db-wal + forcedelete test2.db test2.db-wal do_test walcrash-4.$i.1 { crashsql -delay 3 -file test.db-wal -seed [incr seed] -blocksize 4096 { @@ -171,8 +171,8 @@ for {set i 1} {$i < $REPEATS} {incr i} { # walcrash-5.* # for {set i 1} {$i < $REPEATS} {incr i} { - file delete -force test.db test.db-wal - file delete -force test2.db test2.db-wal + forcedelete test.db test.db-wal + forcedelete test2.db test2.db-wal do_test walcrash-5.$i.1 { crashsql -delay 11 -file test.db-wal -seed [incr seed] -blocksize 4096 { @@ -212,8 +212,8 @@ for {set i 1} {$i < $REPEATS} {incr i} { # walcrash-6.* # for {set i 1} {$i < $REPEATS} {incr i} { - file delete -force test.db test.db-wal - file delete -force test2.db test2.db-wal + forcedelete test.db test.db-wal + forcedelete test2.db test2.db-wal do_test walcrash-6.$i.1 { crashsql -delay 12 -file test.db-wal -seed [incr seed] -blocksize 512 { @@ -262,7 +262,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { # based on the log file. # for {set i 1} {$i < $REPEATS} {incr i} { - file delete -force test.db test.db-wal + forcedelete test.db test.db-wal # Select a page-size for this test. # diff --git a/test/walfault.test b/test/walfault.test index 3a90f9c6..1b71d78a 100644 --- a/test/walfault.test +++ b/test/walfault.test @@ -465,7 +465,7 @@ do_test walfault-13-pre-1 { COMMIT; } faultsim_save_and_close - file delete sv_test.db-shm + delete_file sv_test.db-shm } {} do_faultsim_test walfault-13.1 -prep { diff --git a/test/walmode.test b/test/walmode.test index 11113c6b..4e14d54d 100644 --- a/test/walmode.test +++ b/test/walmode.test @@ -295,7 +295,7 @@ db close # loaded when sqlite3_prepare_v2() is called to compile the statement. # do_test walmode-7.0 { - file delete -force test.db + forcedelete test.db sqlite3 db test.db execsql { PRAGMA journal_mode = WAL; diff --git a/test/walnoshm.test b/test/walnoshm.test index de059dd5..d4082178 100644 --- a/test/walnoshm.test +++ b/test/walnoshm.test @@ -87,8 +87,8 @@ do_execsql_test 2.1.2 { } {exclusive wal} do_test 2.1.3 { - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal sqlite3 db2 test2.db catchsql { SELECT * FROM t2 } db2 } {1 {unable to open database file}} @@ -104,8 +104,8 @@ do_test 2.1.5 { } {exclusive delete a b c d e f g h} do_test 2.2.1 { - file copy -force test.db test2.db - file copy -force test.db-wal test2.db-wal + forcecopy test.db test2.db + forcecopy test.db-wal test2.db-wal sqlite3 db3 test2.db -vfs tvfsshm sqlite3 db2 test2.db execsql { SELECT * FROM t2 } db3 diff --git a/test/walpersist.test b/test/walpersist.test new file mode 100644 index 00000000..175dcbf8 --- /dev/null +++ b/test/walpersist.test @@ -0,0 +1,73 @@ +# 2011 July 26 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file contains tests for using WAL with persistent WAL file mode. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +set ::testprefix walpersist + +ifcapable !wal { + finish_test + return +} + +do_test walpersist-1.0 { + db eval { + PRAGMA journal_mode=WAL; + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(randomblob(5000)); + } + file exists test.db-wal +} {1} +do_test walpersist-1.1 { + file exists test.db-shm +} {1} +do_test walpersist-1.2 { + db close + list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm] +} {1 0 0} +do_test walpersist-1.3 { + sqlite3 db test.db + db eval {SELECT length(a) FROM t1} +} {5000} +do_test walpersist-1.4 { + list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm] +} {1 1 1} +do_test walpersist-1.5 { + file_control_persist_wal db -1 +} {0 0} +do_test walpersist-1.6 { + file_control_persist_wal db 1 +} {0 1} +do_test walpersist-1.7 { + file_control_persist_wal db -1 +} {0 1} +do_test walpersist-1.8 { + file_control_persist_wal db 0 +} {0 0} +do_test walpersist-1.9 { + file_control_persist_wal db -1 +} {0 0} +do_test walpersist-1.10 { + file_control_persist_wal db 1 +} {0 1} +do_test walpersist-1.11 { + db close + list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm] +} {1 1 1} + + + + +finish_test diff --git a/test/walro.test b/test/walro.test index 60bdce9e..3ae7d53c 100644 --- a/test/walro.test +++ b/test/walro.test @@ -24,6 +24,13 @@ if {$::tcl_platform(platform) != "unix"} { return } +# And only if the build is WAL-capable. +# +ifcapable !wal { + finish_test + return +} + do_multiclient_test tn { # Do not run tests with the connections in the same process. # @@ -136,7 +143,7 @@ do_multiclient_test tn { } {1 {unable to open database file}} # Also test that if the -shm file can be opened for read/write access, - # it is, even if readonly_shm=1 is present in the URI. + # it is not if readonly_shm=1 is present in the URI. do_test 1.3.2.1 { code1 { db close } code2 { db2 close } @@ -144,8 +151,8 @@ do_multiclient_test tn { } {0} do_test 1.3.2.2 { code1 { sqlite3 db file:test.db?readonly_shm=1 } - sql1 { SELECT * FROM t1 } - } {a b c d e f g h i j k l} + csql1 { SELECT * FROM sqlite_master } + } {1 {unable to open database file}} do_test 1.3.2.3 { code1 { db close } close [open test.db-shm w] diff --git a/test/walslow.test b/test/walslow.test index d7269528..83f29228 100644 --- a/test/walslow.test +++ b/test/walslow.test @@ -21,7 +21,7 @@ ifcapable !wal {finish_test ; return } proc reopen_db {} { catch { db close } - file delete -force test.db test.db-wal + forcedelete test.db test.db-wal sqlite3 db test.db execsql { PRAGMA journal_mode = wal } } @@ -53,9 +53,9 @@ for {set seed 1} {$seed<10} {incr seed} { } {ok} do_test walslow-1.seed=$seed.$iTest.3 { - file delete -force testX.db testX.db-wal - file copy test.db testX.db - file copy test.db-wal testX.db-wal + forcedelete testX.db testX.db-wal + copy_file test.db testX.db + copy_file test.db-wal testX.db-wal sqlite3 db2 testX.db execsql { PRAGMA journal_mode = WAL } db2 diff --git a/test/walthread.test b/test/walthread.test index 9817c0e0..cbd63718 100644 --- a/test/walthread.test +++ b/test/walthread.test @@ -129,7 +129,7 @@ proc do_thread_test {args} { puts "Running $P(testname) for $P(seconds) seconds..." catch { db close } - file delete -force test.db test.db-journal test.db-wal + forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db eval $P(init) @@ -508,12 +508,12 @@ do_thread_test walthread-5 -seconds $seconds(walthread-5) -init { COMMIT; } - file copy -force test.db-wal bak.db-wal - file copy -force test.db bak.db + forcecopy test.db-wal bak.db-wal + forcecopy test.db bak.db db close - file copy -force bak.db-wal test.db-wal - file copy -force bak.db test.db + forcecopy bak.db-wal test.db-wal + forcecopy bak.db test.db if {[file size test.db-wal] < [log_file_size [expr 64*1024] 1024]} { error "Somehow failed to create a large log file" diff --git a/test/where3.test b/test/where3.test index ab75fdec..e08f9051 100644 --- a/test/where3.test +++ b/test/where3.test @@ -342,4 +342,87 @@ do_execsql_test where3-5.3 { 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } +# Name resolution with NATURAL JOIN and USING +# +do_test where3-6.setup { + db eval { + CREATE TABLE t6w(a, w); + INSERT INTO t6w VALUES(1, 'w-one'); + INSERT INTO t6w VALUES(2, 'w-two'); + INSERT INTO t6w VALUES(9, 'w-nine'); + CREATE TABLE t6x(a, x); + INSERT INTO t6x VALUES(1, 'x-one'); + INSERT INTO t6x VALUES(3, 'x-three'); + INSERT INTO t6x VALUES(9, 'x-nine'); + CREATE TABLE t6y(a, y); + INSERT INTO t6y VALUES(1, 'y-one'); + INSERT INTO t6y VALUES(4, 'y-four'); + INSERT INTO t6y VALUES(9, 'y-nine'); + CREATE TABLE t6z(a, z); + INSERT INTO t6z VALUES(1, 'z-one'); + INSERT INTO t6z VALUES(5, 'z-five'); + INSERT INTO t6z VALUES(9, 'z-nine'); + } +} {} +set cnt 0 +foreach predicate { + {} + {ORDER BY a} + {ORDER BY t6w.a} + {WHERE a>0} + {WHERE t6y.a>0} + {WHERE a>0 ORDER BY a} +} { + incr cnt + do_test where3-6.$cnt.1 { + set sql "SELECT * FROM t6w NATURAL JOIN t6x NATURAL JOIN t6y" + append sql " NATURAL JOIN t6z " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} + do_test where3-6.$cnt.2 { + set sql "SELECT * FROM t6w JOIN t6x USING(a) JOIN t6y USING(a)" + append sql " JOIN t6z USING(a) " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} + do_test where3-6.$cnt.3 { + set sql "SELECT * FROM t6w NATURAL JOIN t6x JOIN t6y USING(a)" + append sql " JOIN t6z USING(a) " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} + do_test where3-6.$cnt.4 { + set sql "SELECT * FROM t6w JOIN t6x USING(a) NATURAL JOIN t6y" + append sql " JOIN t6z USING(a) " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} + do_test where3-6.$cnt.5 { + set sql "SELECT * FROM t6w JOIN t6x USING(a) JOIN t6y USING(a)" + append sql " NATURAL JOIN t6z " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} + do_test where3-6.$cnt.6 { + set sql "SELECT * FROM t6w JOIN t6x USING(a) NATURAL JOIN t6y" + append sql " NATURAL JOIN t6z " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} + do_test where3-6.$cnt.7 { + set sql "SELECT * FROM t6w NATURAL JOIN t6x JOIN t6y USING(a)" + append sql " NATURAL JOIN t6z " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} + do_test where3-6.$cnt.8 { + set sql "SELECT * FROM t6w NATURAL JOIN t6x NATURAL JOIN t6y" + append sql " JOIN t6z USING(a) " + append sql $::predicate + db eval $sql + } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} +} + + finish_test diff --git a/test/where7.test b/test/where7.test index e34778c7..ffb7173d 100644 --- a/test/where7.test +++ b/test/where7.test @@ -10,8 +10,6 @@ #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the multi-index OR clause optimizer. -# -# $Id: where7.test,v 1.9 2009/06/07 23:45:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -23341,7 +23339,7 @@ do_execsql_test where7-3.1 { OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { - 0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?) (~10 rows)} + 0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?) (~5 rows)} 0 0 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} 0 1 0 {SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?) (~2 rows)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} diff --git a/test/where9.test b/test/where9.test index 9a180116..b4a2d8d1 100644 --- a/test/where9.test +++ b/test/where9.test @@ -11,7 +11,6 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the multi-index OR clause optimizer. # -# $Id: where9.test,v 1.9 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -365,7 +364,7 @@ ifcapable explain { } { 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)} - 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)} + 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~5 rows)} } do_execsql_test where9-3.2 { EXPLAIN QUERY PLAN @@ -375,7 +374,7 @@ ifcapable explain { } { 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)} - 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)} + 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~5 rows)} } } @@ -454,8 +453,8 @@ ifcapable explain { do_execsql_test where9-5.1 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL) } { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?) (~10 rows)} - 0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?) (~2 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?) (~2 rows)} } # In contrast, b=1000 is preferred over any OR-clause. @@ -783,4 +782,79 @@ do_test where9-6.8.2 { } } {1 {cannot use index: t1b}} +############################################################################ +# Test cases where terms inside an OR series are combined with AND terms +# external to the OR clause. In other words, cases where +# +# x AND (y OR z) +# +# is able to use indices on x,y and x,z, or indices y,x and z,x. +# +do_test where9-7.0 { + execsql { + CREATE TABLE t5(a, b, c, d, e, f, g, x, y); + INSERT INTO t5 + SELECT a, b, c, e, d, f, g, + CASE WHEN (a&1)!=0 THEN 'y' ELSE 'n' END, + CASE WHEN (a&2)!=0 THEN 'y' ELSE 'n' END + FROM t1; + CREATE INDEX t5xb ON t5(x, b); + CREATE INDEX t5xc ON t5(x, c); + CREATE INDEX t5xd ON t5(x, d); + CREATE INDEX t5xe ON t5(x, e); + CREATE INDEX t5xf ON t5(x, f); + CREATE INDEX t5xg ON t5(x, g); + CREATE INDEX t5yb ON t5(y, b); + CREATE INDEX t5yc ON t5(y, c); + CREATE INDEX t5yd ON t5(y, d); + CREATE INDEX t5ye ON t5(y, e); + CREATE INDEX t5yf ON t5(y, f); + CREATE INDEX t5yg ON t5(y, g); + CREATE TABLE t6(a, b, c, e, d, f, g, x, y); + INSERT INTO t6 SELECT * FROM t5; + ANALYZE t5; + } +} {} +do_test where9-7.1.1 { + count_steps { + SELECT a FROM t5 WHERE x='y' AND (b=913 OR c=27027) ORDER BY a; + } +} {79 81 83 scan 0 sort 1} +do_test where9-7.1.2 { + execsql { + SELECT a FROM t6 WHERE x='y' AND (b=913 OR c=27027) ORDER BY a; + } +} {79 81 83} +do_test where9-7.1.3 { + count_steps { + SELECT a FROM t5 WHERE x='n' AND (b=913 OR c=27027) ORDER BY a; + } +} {80 scan 0 sort 1} +do_test where9-7.1.4 { + execsql { + SELECT a FROM t6 WHERE x='n' AND (b=913 OR c=27027) ORDER BY a; + } +} {80} +do_test where9-7.2.1 { + count_steps { + SELECT a FROM t5 WHERE (x='y' OR y='y') AND b=913 ORDER BY a; + } +} {83 scan 0 sort 1} +do_test where9-7.2.2 { + execsql { + SELECT a FROM t6 WHERE (x='y' OR y='y') AND b=913 ORDER BY a; + } +} {83} +do_test where9-7.3.1 { + count_steps { + SELECT a FROM t5 WHERE (x='y' OR y='y') AND c=27027 ORDER BY a; + } +} {79 81 scan 0 sort 1} +do_test where9-7.3.2 { + execsql { + SELECT a FROM t6 WHERE (x='y' OR y='y') AND c=27027 ORDER BY a; + } +} {79 81} + + finish_test diff --git a/test/win32lock.test b/test/win32lock.test new file mode 100644 index 00000000..d014be4d --- /dev/null +++ b/test/win32lock.test @@ -0,0 +1,133 @@ +# 2011 July 11 +# +# 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 recovery from transient manditory locks +# that sometimes appear on database files due to anti-virus software. +# + +if {$tcl_platform(platform)!="windows"} return + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +set testprefix win32lock + +db close +sqlite3_shutdown +test_sqlite3_log xLog +proc xLog {error_code msg} { + lappend ::log $msg +} +sqlite3 db test.db + +do_test win32lock-1.1 { + db eval { + PRAGMA cache_size=10; + CREATE TABLE t1(x,y); + INSERT INTO t1 VALUES(1,randomblob(100000)); + INSERT INTO t1 VALUES(2,randomblob(50000)); + INSERT INTO t1 VALUES(3,randomblob(25000)); + INSERT INTO t1 VALUES(4,randomblob(12500)); + SELECT x, length(y) FROM t1 ORDER BY rowid; + } +} {1 100000 2 50000 3 25000 4 12500} + +unset -nocomplain delay1 rc msg +set old_pending_byte [sqlite3_test_control_pending_byte 0x40000000] + +set win32_lock_ok [list] +set win32_lock_error [list] +set delay1 25 +while {1} { + lock_win32_file test.db 0 $::delay1 + set ::log {} + set rc [catch {db eval {SELECT x, length(y) FROM t1 ORDER BY rowid}} msg] + if {$rc} { + lappend win32_lock_error $::delay1 + do_test win32lock-1.2-$delay1-error { + set ::msg + } {disk I/O error} + } else { + lappend win32_lock_ok $::delay1 + do_test win32lock-1.2-$delay1-ok { + set ::msg + } {1 100000 2 50000 3 25000 4 12500} + if {[info exists ::log] && $::log!=""} { + do_test win32lock-1.2-$delay1-log1 { + regsub {\d+} $::log # x + set x + } {{delayed #ms for lock/sharing conflict}} + } + } + if {[llength $win32_lock_ok] && [llength $win32_lock_error]} break + incr delay1 25 + if {$delay1 > 12500} { + puts "Timed out waiting for \"ok\" and \"error\" results." + break + } + sqlite3_sleep 10 +} + +do_test win32lock-2.0 { + file_control_win32_av_retry db -1 -1 +} {0 10 25} +do_test win32lock-2.1 { + file_control_win32_av_retry db 1 1 +} {0 1 1} + +# +# NOTE: It is known that the win32lock-2.2-* tests may fail if the system is +# experiencing heavy load (i.e. they are very timing sensitive). This is +# primarily due to the AV retry delay being set to 1 millisecond in the +# win32lock-2.1 test (above). While it is important to test this corner +# case for the AV retry logic, a failure of this test should probably not +# be interpreted as a bug in SQLite or these test cases. +# +set win32_lock_ok [list] +set win32_lock_error [list] +set delay1 1 +while {1} { + lock_win32_file test.db 0 $::delay1 + set ::log {} + set rc [catch {db eval {SELECT x, length(y) FROM t1 ORDER BY rowid}} msg] + if {$rc} { + lappend win32_lock_error $::delay1 + do_test win32lock-2.2-$delay1-error { + set ::msg + } {disk I/O error} + } else { + lappend win32_lock_ok $::delay1 + do_test win32lock-2.2-$delay1-ok { + set ::msg + } {1 100000 2 50000 3 25000 4 12500} + if {[info exists ::log] && $::log!=""} { + do_test win32lock-2.2-$delay1-log1 { + regsub {\d+} $::log # x + set x + } {{delayed #ms for lock/sharing conflict}} + } + } + if {[llength $win32_lock_ok] && [llength $win32_lock_error]} break + incr delay1 1 + if {$delay1 > 500} { + puts "Timed out waiting for \"ok\" and \"error\" results." + break + } + sqlite3_sleep 10 +} + +file_control_win32_av_retry db 10 25 +sqlite3_test_control_pending_byte $old_pending_byte +db close +sqlite3_shutdown +test_sqlite3_log +sqlite3_initialize +finish_test diff --git a/tool/extract.c b/tool/extract.c new file mode 100644 index 00000000..5bf5caa3 --- /dev/null +++ b/tool/extract.c @@ -0,0 +1,46 @@ +/* +** Extract a range of bytes from a file. +** +** Usage: +** +** extract FILENAME OFFSET AMOUNT +** +** The bytes are written to standard output. +*/ +#include +#include + +int main(int argc, char **argv){ + FILE *f; + char *zBuf; + int ofst; + int n; + size_t got; + + if( argc!=4 ){ + fprintf(stderr, "Usage: %s FILENAME OFFSET AMOUNT\n", *argv); + return 1; + } + f = fopen(argv[1], "rb"); + if( f==0 ){ + fprintf(stderr, "cannot open \"%s\"\n", argv[1]); + return 1; + } + ofst = atoi(argv[2]); + n = atoi(argv[3]); + zBuf = malloc( n ); + if( zBuf==0 ){ + fprintf(stderr, "out of memory\n"); + return 1; + } + fseek(f, ofst, SEEK_SET); + got = fread(zBuf, 1, n, f); + fclose(f); + if( goterrorcnt++; + fclose(fp); return; } if( fread(filebuf,1,filesize,fp)!=filesize ){ @@ -2529,6 +2530,7 @@ void Parse(struct lemon *gp) filesize); free(filebuf); gp->errorcnt++; + fclose(fp); return; } fclose(fp); diff --git a/tool/mksqlite3c-noext.tcl b/tool/mksqlite3c-noext.tcl new file mode 100644 index 00000000..6ad30237 --- /dev/null +++ b/tool/mksqlite3c-noext.tcl @@ -0,0 +1,308 @@ +#!/usr/bin/tclsh +# +# To build a single huge source file holding all of SQLite (or at +# least the core components - the test harness, shell, and TCL +# interface are omitted.) first do +# +# make target_source +# +# The make target above moves all of the source code files into +# a subdirectory named "tsrc". (This script expects to find the files +# there and will not work if they are not found.) There are a few +# generated C code files that are also added to the tsrc directory. +# For example, the "parse.c" and "parse.h" files to implement the +# the parser are derived from "parse.y" using lemon. And the +# "keywordhash.h" files is generated by a program named "mkkeywordhash". +# +# After the "tsrc" directory has been created and populated, run +# this script: +# +# tclsh mksqlite3c.tcl +# +# The amalgamated SQLite code will be written into sqlite3.c +# + +# Begin by reading the "sqlite3.h" header file. Extract the version number +# from in this file. The versioon number is needed to generate the header +# comment of the amalgamation. +# +if {[lsearch $argv --nostatic]>=0} { + set addstatic 0 +} else { + set addstatic 1 +} +if {[lsearch $argv --linemacros]>=0} { + set linemacros 1 +} else { + set linemacros 0 +} +set in [open tsrc/sqlite3.h] +set cnt 0 +set VERSION ????? +while {![eof $in]} { + set line [gets $in] + if {$line=="" && [eof $in]} break + incr cnt + regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION +} +close $in + +# Open the output file and write a header comment at the beginning +# of the file. +# +set out [open sqlite3.c w] +# Force the output to use unix line endings, even on Windows. +fconfigure $out -translation lf +set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1] +puts $out [subst \ +{/****************************************************************************** +** This file is an amalgamation of many separate C source files from SQLite +** version $VERSION. By combining all the individual C code files into this +** single large file, the entire code can be compiled as a single translation +** unit. This allows many compilers to do optimizations that would not be +** possible if the files were compiled separately. Performance improvements +** of 5% or more are commonly seen when SQLite is compiled as a single +** translation unit. +** +** This file is all you need to compile SQLite. To use SQLite in other +** programs, you need this file and the "sqlite3.h" header file that defines +** the programming interface to the SQLite library. (If you do not have +** the "sqlite3.h" header file at hand, you will find a copy embedded within +** the text of this file. Search for "Begin file sqlite3.h" to find the start +** of the embedded sqlite3.h header file.) Additional code files may be needed +** if you want a wrapper to interface SQLite with your choice of programming +** language. The code for the "sqlite3" command-line shell is also in a +** separate file. This file contains only code for the core SQLite library. +*/ +#define SQLITE_CORE 1 +#define SQLITE_AMALGAMATION 1}] +if {$addstatic} { + puts $out \ +{#ifndef SQLITE_PRIVATE +# define SQLITE_PRIVATE static +#endif +#ifndef SQLITE_API +# define SQLITE_API +#endif} +} + +# These are the header files used by SQLite. The first time any of these +# files are seen in a #include statement in the C code, include the complete +# text of the file in-line. The file only needs to be included once. +# +foreach hdr { + btree.h + btreeInt.h + hash.h + hwtime.h + keywordhash.h + mutex.h + opcodes.h + os_common.h + os.h + os_os2.h + pager.h + parse.h + pcache.h + sqlite3ext.h + sqlite3.h + sqliteicu.h + sqliteInt.h + sqliteLimit.h + vdbe.h + vdbeInt.h + wal.h +} { + set available_hdr($hdr) 1 +} +set available_hdr(sqliteInt.h) 0 + +# 78 stars used for comment formatting. +set s78 \ +{*****************************************************************************} + +# Insert a comment into the code +# +proc section_comment {text} { + global out s78 + set n [string length $text] + set nstar [expr {60 - $n}] + set stars [string range $s78 0 $nstar] + puts $out "/************** $text $stars/" +} + +# Read the source file named $filename and write it into the +# sqlite3.c output file. If any #include statements are seen, +# process them approprately. +# +proc copy_file {filename} { + global seen_hdr available_hdr out addstatic linemacros + set ln 0 + set tail [file tail $filename] + section_comment "Begin file $tail" + if {$linemacros} {puts $out "#line 1 \"$filename\""} + set in [open $filename r] + set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)} + set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \**(sqlite3[_a-zA-Z0-9]+)\(} + if {[file extension $filename]==".h"} { + set declpattern " *$declpattern" + } + set declpattern ^$declpattern + while {![eof $in]} { + set line [gets $in] + incr ln + if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { + if {[info exists available_hdr($hdr)]} { + if {$available_hdr($hdr)} { + if {$hdr!="os_common.h" && $hdr!="hwtime.h"} { + set available_hdr($hdr) 0 + } + section_comment "Include $hdr in the middle of $tail" + copy_file tsrc/$hdr + section_comment "Continuing where we left off in $tail" + if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""} + } + } elseif {![info exists seen_hdr($hdr)]} { + set seen_hdr($hdr) 1 + puts $out $line + } else { + puts $out "/* $line */" + } + } elseif {[regexp {^#ifdef __cplusplus} $line]} { + puts $out "#if 0" + } elseif {!$linemacros && [regexp {^#line} $line]} { + # Skip #line directives. + } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { + regsub {^SQLITE_API } $line {} line + if {[regexp $declpattern $line all funcname]} { + # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. + # so that linkage can be modified at compile-time. + if {[regexp {^sqlite3_} $funcname]} { + puts $out "SQLITE_API $line" + } else { + puts $out "SQLITE_PRIVATE $line" + } + } elseif {[regexp $varpattern $line all varname]} { + # Add the SQLITE_PRIVATE before variable declarations or + # definitions for internal use + if {![regexp {^sqlite3_} $varname]} { + regsub {^extern } $line {} line + puts $out "SQLITE_PRIVATE $line" + } else { + if {[regexp {const char sqlite3_version\[\];} $line]} { + set line {const char sqlite3_version[] = SQLITE_VERSION;} + } + regsub {^SQLITE_EXTERN } $line {} line + puts $out "SQLITE_API $line" + } + } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} { + regsub {^SQLITE_EXTERN } $line {} line + puts $out "SQLITE_PRIVATE $line" + } elseif {[regexp {^void \(\*sqlite3Os} $line]} { + puts $out "SQLITE_PRIVATE $line" + } else { + puts $out $line + } + } else { + puts $out $line + } + } + close $in + section_comment "End of $tail" +} + + +# Process the source files. Process files containing commonly +# used subroutines first in order to help the compiler find +# inlining opportunities. +# +foreach file { + sqliteInt.h + + global.c + ctime.c + status.c + date.c + os.c + + fault.c + mem0.c + mem1.c + mem2.c + mem3.c + mem5.c + mutex.c + mutex_noop.c + mutex_os2.c + mutex_unix.c + mutex_w32.c + malloc.c + printf.c + random.c + utf.c + util.c + hash.c + opcodes.c + + os_os2.c + os_unix.c + os_win.c + + bitvec.c + pcache.c + pcache1.c + rowset.c + pager.c + wal.c + + btmutex.c + btree.c + backup.c + + vdbemem.c + vdbeaux.c + vdbeapi.c + vdbetrace.c + vdbe.c + vdbeblob.c + vdbesort.c + journal.c + memjournal.c + + walker.c + resolve.c + expr.c + alter.c + analyze.c + attach.c + auth.c + build.c + callback.c + delete.c + func.c + fkey.c + insert.c + legacy.c + loadext.c + pragma.c + prepare.c + select.c + table.c + trigger.c + update.c + vacuum.c + vtab.c + where.c + + parse.c + + tokenize.c + complete.c + + main.c + notify.c +} { + copy_file tsrc/$file +} + +close $out diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index ab7efcc0..09ebb7c0 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -31,6 +31,11 @@ if {[lsearch $argv --nostatic]>=0} { } else { set addstatic 1 } +if {[lsearch $argv --linemacros]>=0} { + set linemacros 1 +} else { + set linemacros 0 +} set in [open tsrc/sqlite3.h] set cnt 0 set VERSION ????? @@ -137,9 +142,11 @@ proc section_comment {text} { # process them approprately. # proc copy_file {filename} { - global seen_hdr available_hdr out addstatic + global seen_hdr available_hdr out addstatic linemacros + set ln 0 set tail [file tail $filename] section_comment "Begin file $tail" + if {$linemacros} {puts $out "#line 1 \"$filename\""} set in [open $filename r] set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)} set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \**(sqlite3[_a-zA-Z0-9]+)\(} @@ -149,6 +156,7 @@ proc copy_file {filename} { set declpattern ^$declpattern while {![eof $in]} { set line [gets $in] + incr ln if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { if {[info exists available_hdr($hdr)]} { if {$available_hdr($hdr)} { @@ -158,14 +166,17 @@ proc copy_file {filename} { section_comment "Include $hdr in the middle of $tail" copy_file tsrc/$hdr section_comment "Continuing where we left off in $tail" + if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""} } } elseif {![info exists seen_hdr($hdr)]} { set seen_hdr($hdr) 1 puts $out $line + } else { + puts $out "/* $line */" } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" - } elseif {[regexp {^#line} $line]} { + } elseif {!$linemacros && [regexp {^#line} $line]} { # Skip #line directives. } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { regsub {^SQLITE_API } $line {} line @@ -263,6 +274,7 @@ foreach file { vdbetrace.c vdbe.c vdbeblob.c + vdbesort.c journal.c memjournal.c diff --git a/tool/offsets.c b/tool/offsets.c new file mode 100644 index 00000000..8e098e71 --- /dev/null +++ b/tool/offsets.c @@ -0,0 +1,329 @@ +/* +** This program searches an SQLite database file for the lengths and +** offsets for all TEXT or BLOB entries for a particular column of a +** particular table. The rowid, size and offset for the column are +** written to standard output. There are three arguments, which are the +** name of the database file, the table, and the column. +*/ +#include "sqlite3.h" +#include +#include +#include +#include + +typedef unsigned char u8; +typedef struct GState GState; + +#define ArraySize(X) (sizeof(X)/sizeof(X[0])) + +/* +** Global state information for this program. +*/ +struct GState { + char *zErr; /* Error message text */ + FILE *f; /* Open database file */ + int szPg; /* Page size for the database file */ + int iRoot; /* Root page of the table */ + int iCol; /* Column number for the column */ + int pgno; /* Current page number */ + u8 *aPage; /* Current page content */ + u8 *aStack[20]; /* Page stack */ + int aPgno[20]; /* Page number stack */ + int nStack; /* Depth of stack */ + int bTrace; /* True for tracing output */ +}; + +/* +** Write an error. +*/ +static void ofstError(GState *p, const char *zFormat, ...){ + va_list ap; + sqlite3_free(p->zErr); + va_start(ap, zFormat); + p->zErr = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + +/* +** Write a trace message +*/ +static void ofstTrace(GState *p, const char *zFormat, ...){ + va_list ap; + if( p->bTrace ){ + va_start(ap, zFormat); + vprintf(zFormat, ap); + va_end(ap); + } +} + +/* +** Find the root page of the table and the column number of the column. +*/ +static void ofstRootAndColumn( + GState *p, /* Global state */ + const char *zFile, /* Name of the database file */ + const char *zTable, /* Name of the table */ + const char *zColumn /* Name of the column */ +){ + sqlite3 *db = 0; + sqlite3_stmt *pStmt = 0; + char *zSql = 0; + int rc; + if( p->zErr ) return; + rc = sqlite3_open(zFile, &db); + if( rc ){ + ofstError(p, "cannot open database file \"%s\"", zFile); + goto rootAndColumn_exit; + } + zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master WHERE name=%Q", + zTable); + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql); + sqlite3_free(zSql); + if( p->zErr ) goto rootAndColumn_exit; + if( sqlite3_step(pStmt)!=SQLITE_ROW ){ + ofstError(p, "cannot find table [%s]\n", zTable); + sqlite3_finalize(pStmt); + goto rootAndColumn_exit; + } + p->iRoot = sqlite3_column_int(pStmt , 0); + sqlite3_finalize(pStmt); + + p->iCol = -1; + zSql = sqlite3_mprintf("PRAGMA table_info(%Q)", zTable); + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc ) ofstError(p, "%s: [%s}", sqlite3_errmsg(db), zSql); + sqlite3_free(zSql); + if( p->zErr ) goto rootAndColumn_exit; + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zCol = sqlite3_column_text(pStmt, 1); + if( strlen(zCol)==strlen(zColumn) + && sqlite3_strnicmp(zCol, zColumn, strlen(zCol))==0 + ){ + p->iCol = sqlite3_column_int(pStmt, 0); + break; + } + } + sqlite3_finalize(pStmt); + if( p->iCol<0 ){ + ofstError(p, "no such column: %s.%s", zTable, zColumn); + goto rootAndColumn_exit; + } + + zSql = sqlite3_mprintf("PRAGMA page_size"); + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql); + sqlite3_free(zSql); + if( p->zErr ) goto rootAndColumn_exit; + if( sqlite3_step(pStmt)!=SQLITE_ROW ){ + ofstError(p, "cannot find page size"); + }else{ + p->szPg = sqlite3_column_int(pStmt, 0); + } + sqlite3_finalize(pStmt); + +rootAndColumn_exit: + sqlite3_close(db); + return; +} + +/* +** Pop a page from the stack +*/ +static void ofstPopPage(GState *p){ + if( p->nStack<=0 ) return; + p->nStack--; + sqlite3_free(p->aStack[p->nStack]); + p->pgno = p->aPgno[p->nStack-1]; + p->aPage = p->aStack[p->nStack-1]; +} + + +/* +** Push a new page onto the stack. +*/ +static void ofstPushPage(GState *p, int pgno){ + u8 *pPage; + size_t got; + if( p->zErr ) return; + if( p->nStack >= ArraySize(p->aStack) ){ + ofstError(p, "page stack overflow"); + return; + } + p->aPgno[p->nStack] = pgno; + p->aStack[p->nStack] = pPage = sqlite3_malloc( p->szPg ); + if( pPage==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } + p->nStack++; + p->aPage = pPage; + p->pgno = pgno; + fseek(p->f, (pgno-1)*p->szPg, SEEK_SET); + got = fread(pPage, 1, p->szPg, p->f); + if( got!=p->szPg ){ + ofstError(p, "unable to read page %d", pgno); + ofstPopPage(p); + } +} + +/* Read a two-byte integer at the given offset into the current page */ +static int ofst2byte(GState *p, int ofst){ + int x = p->aPage[ofst]; + return (x<<8) + p->aPage[ofst+1]; +} + +/* Read a four-byte integer at the given offset into the current page */ +static int ofst4byte(GState *p, int ofst){ + int x = p->aPage[ofst]; + x = (x<<8) + p->aPage[ofst+1]; + x = (x<<8) + p->aPage[ofst+2]; + x = (x<<8) + p->aPage[ofst+3]; + return x; +} + +/* Read a variable-length integer. Update the offset */ +static sqlite3_int64 ofstVarint(GState *p, int *pOfst){ + sqlite3_int64 x = 0; + u8 *a = &p->aPage[*pOfst]; + int n = 0; + while( n<8 && (a[0] & 0x80)!=0 ){ + x = (x<<7) + (a[0] & 0x7f); + n++; + a++; + } + if( n==8 ){ + x = (x<<8) + a[0]; + }else{ + x = (x<<7) + a[0]; + } + *pOfst += (n+1); + return x; +} + +/* Return the absolute offset into a file for the given offset +** into the current page */ +static int ofstInFile(GState *p, int ofst){ + return p->szPg*(p->pgno-1) + ofst; +} + +/* Return the size (in bytes) of the data corresponding to the +** given serial code */ +static int ofstSerialSize(int scode){ + if( scode<5 ) return scode; + if( scode==5 ) return 6; + if( scode<8 ) return 8; + if( scode<12 ) return 0; + return (scode-12)/2; +} + +/* Forward reference */ +static void ofstWalkPage(GState*, int); + +/* Walk an interior btree page */ +static void ofstWalkInteriorPage(GState *p){ + int nCell; + int i; + int ofst; + int iChild; + + nCell = ofst2byte(p, 3); + for(i=0; izErr ) return; + } + ofstWalkPage(p, ofst4byte(p, 8)); +} + +/* Walk a leaf btree page */ +static void ofstWalkLeafPage(GState *p){ + int nCell; + int i; + int ofst; + int nPayload; + sqlite3_int64 rowid; + int nHdr; + int j; + int scode; + int sz; + int dataOfst; + char zMsg[200]; + + nCell = ofst2byte(p, 3); + for(i=0; i p->szPg-35 ){ + sqlite3_snprintf(sizeof(zMsg), zMsg, + "# overflow rowid %lld", rowid); + printf("%s\n", zMsg); + continue; + } + dataOfst = ofst; + nHdr = ofstVarint(p, &ofst); + dataOfst += nHdr; + for(j=0; jiCol; j++){ + scode = ofstVarint(p, &ofst); + dataOfst += ofstSerialSize(scode); + } + scode = ofstVarint(p, &ofst); + sz = ofstSerialSize(scode); + sqlite3_snprintf(sizeof(zMsg), zMsg, + "rowid %12lld size %5d offset %8d", + rowid, sz, ofstInFile(p, dataOfst)); + printf("%s\n", zMsg); + } +} + +/* +** Output results from a single page. +*/ +static void ofstWalkPage(GState *p, int pgno){ + if( p->zErr ) return; + ofstPushPage(p, pgno); + if( p->zErr ) return; + if( p->aPage[0]==5 ){ + ofstWalkInteriorPage(p); + }else if( p->aPage[0]==13 ){ + ofstWalkLeafPage(p); + }else{ + ofstError(p, "page %d has a faulty type byte: %d", pgno, p->aPage[0]); + } + ofstPopPage(p); +} + +int main(int argc, char **argv){ + GState g; + memset(&g, 0, sizeof(g)); + if( argc>2 && strcmp(argv[1],"--trace")==0 ){ + g.bTrace = 1; + argc--; + argv++; + } + if( argc!=4 ){ + fprintf(stderr, "Usage: %s DATABASE TABLE COLUMN\n", *argv); + exit(1); + } + ofstRootAndColumn(&g, argv[1], argv[2], argv[3]); + if( g.zErr ){ + fprintf(stderr, "%s\n", g.zErr); + exit(1); + } + ofstTrace(&g, "# szPg = %d\n", g.szPg); + ofstTrace(&g, "# iRoot = %d\n", g.iRoot); + ofstTrace(&g, "# iCol = %d\n", g.iCol); + g.f = fopen(argv[1], "rb"); + if( g.f==0 ){ + fprintf(stderr, "cannot open \"%s\"\n", argv[1]); + exit(1); + } + ofstWalkPage(&g, g.iRoot); + if( g.zErr ){ + fprintf(stderr, "%s\n", g.zErr); + exit(1); + } + return 0; +} diff --git a/tool/omittest.tcl b/tool/omittest.tcl index 33a71cee..7f13a4cb 100644 --- a/tool/omittest.tcl +++ b/tool/omittest.tcl @@ -48,19 +48,18 @@ they do not respect the OPTS variable. # # proc run_quick_test {dir omit_symbol_list} { - set target "testfixture" # Compile the value of the OPTS Makefile variable. - set opts "-DSQLITE_MEMDEBUG -DSQLITE_DEBUG -DSQLITE_NO_SYNC" + set opts "" if {$::tcl_platform(platform)=="windows"} { - append opts " -DSQLITE_OS_WIN=1" + append opts "OPTS += -DSQLITE_OS_WIN=1\n" set target "testfixture.exe" } elseif {$::tcl_platform(platform)=="os2"} { - append opts " -DSQLITE_OS_OS2=1" + append opts "OPTS += -DSQLITE_OS_OS2=1\n" } else { - append opts " -DSQLITE_OS_UNIX=1" + append opts "OPTS += -DSQLITE_OS_UNIX=1\n" } foreach sym $omit_symbol_list { - append opts " -D${sym}=1" + append opts "OPTS += -D${sym}=1\n" } # Create the directory and do the build. If an error occurs return @@ -68,12 +67,20 @@ proc run_quick_test {dir omit_symbol_list} { file mkdir $dir puts -nonewline "Building $dir..." flush stdout -catch { - file copy -force ./config.h $dir - file copy -force ./libtool $dir -} + catch { + file copy -force ./config.h $dir + file copy -force ./libtool $dir + } + set fd [open $::MAKEFILE] + set mkfile [read $fd] + close $fd + regsub {\ninclude} $mkfile "\n$opts\ninclude" mkfile + set fd [open $dir/makefile w] + puts $fd $mkfile + close $fd + set rc [catch { - exec $::MAKEBIN -C $dir -f $::MAKEFILE clean $target OPTS=$opts >& $dir/build.log + exec $::MAKEBIN -C $dir -f makefile clean $::TARGET >& $dir/build.log }] if {$rc} { puts "No good. See $dir/build.log." @@ -102,7 +109,7 @@ catch { puts -nonewline "Testing $dir..." flush stdout set rc [catch { - exec $::MAKEBIN -C $dir -f $::MAKEFILE test OPTS=$opts >& $dir/test.log + exec $::MAKEBIN -C $dir -f makefile test >& $dir/test.log }] if {$rc} { puts "No good. See $dir/test.log." @@ -126,6 +133,7 @@ proc process_options {argv} { set ::MAKEFILE ./Makefile.linux-gcc ;# Default value } set ::SKIP_RUN 0 ;# Default to attempt test + set ::TARGET testfixture ;# Default thing to build for {set i 0} {$i < [llength $argv]} {incr i} { switch -- [lindex $argv $i] { @@ -139,6 +147,11 @@ proc process_options {argv} { set ::MAKEFILE ./Makefile.msc } + -target { + incr i + set ::TARGET [lindex $argv $i] + } + -skip_run { set ::SKIP_RUN 1 } @@ -182,7 +195,6 @@ proc main {argv} { SQLITE_OMIT_DATETIME_FUNCS \ SQLITE_OMIT_DECLTYPE \ SQLITE_OMIT_DEPRECATED \ - xxxSQLITE_OMIT_DISKIO \ SQLITE_OMIT_EXPLAIN \ SQLITE_OMIT_FLAG_PRAGMAS \ SQLITE_OMIT_FLOATING_POINT \ @@ -224,15 +236,11 @@ proc main {argv} { SQLITE_DISABLE_DIRSYNC \ SQLITE_DISABLE_LFS \ SQLITE_ENABLE_ATOMIC_WRITE \ - xxxSQLITE_ENABLE_CEROD \ SQLITE_ENABLE_COLUMN_METADATA \ SQLITE_ENABLE_EXPENSIVE_ASSERT \ - xxxSQLITE_ENABLE_FTS1 \ - xxxSQLITE_ENABLE_FTS2 \ SQLITE_ENABLE_FTS3 \ SQLITE_ENABLE_FTS3_PARENTHESIS \ SQLITE_ENABLE_FTS4 \ - xxxSQLITE_ENABLE_ICU \ SQLITE_ENABLE_IOTRACE \ SQLITE_ENABLE_LOAD_EXTENSION \ SQLITE_ENABLE_LOCKING_STYLE \ @@ -241,7 +249,7 @@ proc main {argv} { SQLITE_ENABLE_MEMSYS5 \ SQLITE_ENABLE_OVERSIZE_CELL_CHECK \ SQLITE_ENABLE_RTREE \ - SQLITE_ENABLE_STAT2 \ + SQLITE_ENABLE_STAT3 \ SQLITE_ENABLE_UNLOCK_NOTIFY \ SQLITE_ENABLE_UPDATE_DELETE_LIMIT \ ] diff --git a/tool/spaceanal.tcl b/tool/spaceanal.tcl index bf6244e8..3dddfe42 100644 --- a/tool/spaceanal.tcl +++ b/tool/spaceanal.tcl @@ -4,15 +4,32 @@ # if {[catch { - # Get the name of the database to analyze # -#set argv $argv0 -if {[llength $argv]!=1} { +proc usage {} { + set argv0 [file rootname [file tail [info nameofexecutable]]] puts stderr "Usage: $argv0 database-name" exit 1 } -set file_to_analyze [lindex $argv 0] +set file_to_analyze {} +set flags(-pageinfo) 0 +set flags(-stats) 0 +append argv {} +foreach arg $argv { + if {[regexp {^-+pageinfo$} $arg]} { + set flags(-pageinfo) 1 + } elseif {[regexp {^-+stats$} $arg]} { + set flags(-stats) 1 + } elseif {[regexp {^-} $arg]} { + puts stderr "Unknown option: $arg" + usage + } elseif {$file_to_analyze!=""} { + usage + } else { + set file_to_analyze $arg + } +} +if {$file_to_analyze==""} usage if {![file exists $file_to_analyze]} { puts stderr "No such file: $file_to_analyze" exit 1 @@ -21,19 +38,76 @@ if {![file readable $file_to_analyze]} { puts stderr "File is not readable: $file_to_analyze" exit 1 } -if {[file size $file_to_analyze]<512} { +set true_file_size [file size $file_to_analyze] +if {$true_file_size<512} { puts stderr "Empty or malformed database: $file_to_analyze" exit 1 } +# Compute the total file size assuming test_multiplexor is being used. +# Assume that SQLITE_ENABLE_8_3_NAMES might be enabled +# +set extension [file extension $file_to_analyze] +set pattern $file_to_analyze +append pattern {[0-9][0-9]} +foreach f [glob -nocomplain $pattern] { + incr true_file_size [file size $f] + set extension {} +} +if {[string length $extension]>=2 && [string length $extension]<=4} { + set pattern [file rootname $file_to_analyze] + append pattern [string range $extension 0 1] + append pattern {[0-9][0-9]} + foreach f [glob -nocomplain $pattern] { + incr true_file_size [file size $f] + } +} + # Open the database # -sqlite3 db [lindex $argv 0] +sqlite3 db $file_to_analyze register_dbstat_vtab db -set pageSize [db one {PRAGMA page_size}] +db eval {SELECT count(*) FROM sqlite_master} +set pageSize [expr {wide([db one {PRAGMA page_size}])}] -#set DB [btree_open [lindex $argv 0] 1000 0] +if {$flags(-pageinfo)} { + db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat} + db eval {SELECT name, path, pageno FROM temp.stat ORDER BY pageno} { + puts "$pageno $name $path" + } + exit 0 +} +if {$flags(-stats)} { + db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat} + puts "BEGIN;" + puts "CREATE TABLE stats(" + puts " name STRING, /* Name of table or index */" + puts " path INTEGER, /* Path to page from root */" + puts " pageno INTEGER, /* Page number */" + puts " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" + puts " ncell INTEGER, /* Cells on page (0 for overflow) */" + puts " payload INTEGER, /* Bytes of payload on this page */" + puts " unused INTEGER, /* Bytes of unused space on this page */" + puts " mx_payload INTEGER, /* Largest payload size of all cells */" + puts " pgoffset INTEGER, /* Offset of page in file */" + puts " pgsize INTEGER /* Size of the page */" + puts ");" + db eval {SELECT quote(name) || ',' || + quote(path) || ',' || + quote(pageno) || ',' || + quote(pagetype) || ',' || + quote(ncell) || ',' || + quote(payload) || ',' || + quote(unused) || ',' || + quote(mx_payload) || ',' || + quote(pgoffset) || ',' || + quote(pgsize) AS x FROM stat} { + puts "INSERT INTO stats VALUES($x);" + } + puts "COMMIT;" + exit 0 +} # In-memory database for collecting statistics. This script loops through # the tables and indices in the database being analyzed, adding a row for each @@ -41,8 +115,7 @@ set pageSize [db one {PRAGMA page_size}] # queries the in-memory db to produce the space-analysis report. # sqlite3 mem :memory: -set tabledef\ -{CREATE TABLE space_used( +set tabledef {CREATE TABLE space_used( name clob, -- Name of a table or index in the database file tblname clob, -- Name of associated table is_index boolean, -- TRUE if it is an index, false for a table @@ -58,17 +131,17 @@ set tabledef\ int_unused int, -- Number of unused bytes on interior pages leaf_unused int, -- Number of unused bytes on primary pages ovfl_unused int, -- Number of unused bytes on overflow pages - gap_cnt int -- Number of gaps in the page layout + gap_cnt int, -- Number of gaps in the page layout + compressed_size int -- Total bytes stored on disk );} mem eval $tabledef # Create a temporary "dbstat" virtual table. # -db eval { - CREATE VIRTUAL TABLE temp.stat USING dbstat; - CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat ORDER BY name, path; - DROP TABLE temp.stat; -} +db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat} +db eval {CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat + ORDER BY name, path} +db eval {DROP TABLE temp.stat} proc isleaf {pagetype is_index} { return [expr {$pagetype == "leaf" || ($pagetype == "internal" && $is_index)}] @@ -84,6 +157,8 @@ db func isleaf isleaf db func isinternal isinternal db func isoverflow isoverflow +set isCompressed 0 +set compressOverhead 0 set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 } foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { @@ -101,10 +176,18 @@ foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { sum(isoverflow(pagetype, $is_index)) AS ovfl_pages, sum(isinternal(pagetype, $is_index) * unused) AS int_unused, sum(isleaf(pagetype, $is_index) * unused) AS leaf_unused, - sum(isoverflow(pagetype, $is_index) * unused) AS ovfl_unused + sum(isoverflow(pagetype, $is_index) * unused) AS ovfl_unused, + sum(pgsize) AS compressed_size FROM temp.dbstat WHERE name = $name } break + set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}] + set storage [expr {$total_pages*$pageSize}] + if {!$isCompressed && $storage>$compressed_size} { + set isCompressed 1 + set compressOverhead 14 + } + # Column 'gap_cnt' is set to the number of non-contiguous entries in the # list of pages visited if the b-tree structure is traversed in a top-down # fashion (each node visited before its child-tree is passed). Any overflow @@ -138,14 +221,15 @@ foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { $int_unused, $leaf_unused, $ovfl_unused, - $gap_cnt + $gap_cnt, + $compressed_size ); } } proc integerify {real} { if {[string is double -strict $real]} { - return [expr {int($real)}] + return [expr {wide($real)}] } else { return 0 } @@ -200,7 +284,7 @@ proc divide {num denom} { # the $where clause determines which subset to analyze. # proc subreport {title where} { - global pageSize file_pgcnt + global pageSize file_pgcnt compressOverhead # Query the in-memory database for the sum of various statistics # for the subset of tables/indices identified by the WHERE clause in @@ -224,7 +308,8 @@ proc subreport {title where} { int(sum(leaf_unused)) AS leaf_unused, int(sum(int_unused)) AS int_unused, int(sum(ovfl_unused)) AS ovfl_unused, - int(sum(gap_cnt)) AS gap_cnt + int(sum(gap_cnt)) AS gap_cnt, + int(sum(compressed_size)) AS compressed_size FROM space_used WHERE $where" {} {} # Output the sub-report title, nicely decorated with * characters. @@ -274,6 +359,12 @@ proc subreport {title where} { statline {Percentage of total database} $total_pages_percent statline {Number of entries} $nleaf statline {Bytes of storage consumed} $storage + if {$compressed_size!=$storage} { + set compressed_size [expr {$compressed_size+$compressOverhead*$total_pages}] + set pct [expr {$compressed_size*100.0/$storage}] + set pct [format {%5.1f%%} $pct] + statline {Bytes used after compression} $compressed_size $pct + } statline {Bytes of payload} $payload $payload_percent statline {Average payload per entry} $avg_payload statline {Average unused bytes per entry} $avg_unused @@ -293,16 +384,16 @@ proc subreport {title where} { statline {Overflow pages used} $ovfl_pages statline {Total pages used} $total_pages if {$int_unused>0} { - set int_unused_percent \ - [percent $int_unused [expr {$int_pages*$pageSize}] {of index space}] + set int_unused_percent [ + percent $int_unused [expr {$int_pages*$pageSize}] {of index space}] statline "Unused bytes on index pages" $int_unused $int_unused_percent } - statline "Unused bytes on primary pages" $leaf_unused \ - [percent $leaf_unused [expr {$leaf_pages*$pageSize}] {of primary space}] - statline "Unused bytes on overflow pages" $ovfl_unused \ - [percent $ovfl_unused [expr {$ovfl_pages*$pageSize}] {of overflow space}] - statline "Unused bytes on all pages" $total_unused \ - [percent $total_unused $storage {of all space}] + statline "Unused bytes on primary pages" $leaf_unused [ + percent $leaf_unused [expr {$leaf_pages*$pageSize}] {of primary space}] + statline "Unused bytes on overflow pages" $ovfl_unused [ + percent $ovfl_unused [expr {$ovfl_pages*$pageSize}] {of overflow space}] + statline "Unused bytes on all pages" $total_unused [ + percent $total_unused $storage {of all space}] return 1 } @@ -330,7 +421,7 @@ proc autovacuum_overhead {filePages pageSize} { set ptrsPerPage [expr double($pageSize/5)] # Return the number of pointer map pages in the database. - return [expr int(ceil( ($filePages-1.0)/($ptrsPerPage+1.0) ))] + return [expr wide(ceil( ($filePages-1.0)/($ptrsPerPage+1.0) ))] } @@ -357,17 +448,24 @@ proc autovacuum_overhead {filePages pageSize} { # (not including sqlite_master) # user_percent: $user_payload as a percentage of total file size. -set file_bytes [file size $file_to_analyze] -set file_pgcnt [expr {$file_bytes/$pageSize}] +### The following, setting $file_bytes based on the actual size of the file +### on disk, causes this tool to choke on zipvfs databases. So set it based +### on the return of [PRAGMA page_count] instead. +if 0 { + set file_bytes [file size $file_to_analyze] + set file_pgcnt [expr {$file_bytes/$pageSize}] +} +set file_pgcnt [db one {PRAGMA page_count}] +set file_bytes [expr {$file_pgcnt * $pageSize}] set av_pgcnt [autovacuum_overhead $file_pgcnt $pageSize] set av_percent [percent $av_pgcnt $file_pgcnt] set sql {SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM space_used} -set inuse_pgcnt [expr int([mem eval $sql])] +set inuse_pgcnt [expr wide([mem eval $sql])] set inuse_percent [percent $inuse_pgcnt $file_pgcnt] -set free_pgcnt [expr $file_pgcnt-$inuse_pgcnt-$av_pgcnt] +set free_pgcnt [expr {$file_pgcnt-$inuse_pgcnt-$av_pgcnt}] set free_percent [percent $free_pgcnt $file_pgcnt] set free_pgcnt2 [db one {PRAGMA freelist_count}] set free_percent2 [percent $free_pgcnt2 $file_pgcnt] @@ -403,7 +501,13 @@ statline {Number of tables in the database} $ntable statline {Number of indices} $nindex statline {Number of named indices} $nmanindex statline {Automatically generated indices} $nautoindex -statline {Size of the file in bytes} $file_bytes +if {$isCompressed} { + statline {Size of uncompressed content in bytes} $file_bytes + set efficiency [percent $true_file_size $file_bytes] + statline {Size of compressed file on disk} $true_file_size $efficiency +} else { + statline {Size of the file in bytes} $file_bytes +} statline {Bytes of user payload stored} $user_payload $user_percent # Output table rankings @@ -416,6 +520,24 @@ mem eval {SELECT tblname, count(*) AS cnt, FROM space_used GROUP BY tblname ORDER BY size+0 DESC, tblname} {} { statline [string toupper $tblname] $size [percent $size $file_pgcnt] } +if {$isCompressed} { + puts "" + puts "*** Bytes of disk space used after compression ***********************" + puts "" + set csum 0 + mem eval {SELECT tblname, + int(sum(compressed_size)) + + $compressOverhead*sum(int_pages+leaf_pages+ovfl_pages) + AS csize + FROM space_used GROUP BY tblname ORDER BY csize+0 DESC, tblname} {} { + incr csum $csize + statline [string toupper $tblname] $csize [percent $csize $true_file_size] + } + set overhead [expr {$true_file_size - $csum}] + if {$overhead>0} { + statline {Header and free space} $overhead [percent $overhead $true_file_size] + } +} # Output subreports # @@ -452,11 +574,9 @@ Page size in bytes Number of pages in the whole file } -puts \ -" The number of $pageSize-byte pages that go into forming the complete +puts " The number of $pageSize-byte pages that go into forming the complete database" -puts \ -{ +puts { Pages that store data The number of pages that store data, either as primary B*Tree pages or diff --git a/tool/symbols-mingw.sh b/tool/symbols-mingw.sh new file mode 100644 index 00000000..bf93eec7 --- /dev/null +++ b/tool/symbols-mingw.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Run this script in a directory that contains a valid SQLite makefile in +# order to verify that unintentionally exported symbols. +# +make sqlite3.c + +echo '****** Exported symbols from a build including RTREE && FTS4 ******' +gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ + -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ + -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ + -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ + sqlite3.c +nm sqlite3.o | grep " [TD] " + +echo '****** Surplus symbols from a build including RTREE & FTS4 ******' +nm sqlite3.o | grep " [TD] " | grep -v " .*sqlite3_" + +echo '****** Dependencies of the core. No extensions. No OS interface *******' +gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ + -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ + -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ + -DSQLITE_OS_OTHER -DSQLITE_THREADSAFE=0 \ + sqlite3.c +nm sqlite3.o | grep " U " + +echo '****** Dependencies including RTREE & FTS4 *******' +gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ + -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ + -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ + -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ + sqlite3.c +nm sqlite3.o | grep " U " diff --git a/tool/symbols.sh b/tool/symbols.sh index 8aec0056..befffce5 100644 --- a/tool/symbols.sh +++ b/tool/symbols.sh @@ -7,18 +7,18 @@ make sqlite3.c echo '****** Exported symbols from a build including RTREE, FTS4 & ICU ******' gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \ + -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ -DSQLITE_ENABLE_ICU \ sqlite3.c -nm sqlite3.o | grep ' T ' | sort -k 3 +nm sqlite3.o | grep ' [TD] ' | sort -k 3 echo '****** Surplus symbols from a build including RTREE, FTS4 & ICU ******' -nm sqlite3.o | grep ' T ' | grep -v ' sqlite3_' +nm sqlite3.o | grep ' [TD] ' | grep -v ' .*sqlite3_' echo '****** Dependencies of the core. No extensions. No OS interface *******' -gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \ +gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ -DSQLITE_OS_OTHER -DSQLITE_THREADSAFE=0 \ @@ -27,7 +27,7 @@ nm sqlite3.o | grep ' U ' | sort -k 3 echo '****** Dependencies including RTREE & FTS4 *******' gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \ + -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ sqlite3.c diff --git a/tool/tostr.awk b/tool/tostr.awk index 83c6cc1a..b4f48d3d 100644 --- a/tool/tostr.awk +++ b/tool/tostr.awk @@ -3,7 +3,6 @@ # Convert input text into a C string # { - gsub(/\\/,"\\\\"); gsub(/\"/,"\\\""); print "\"" $0 "\\n\""; } diff --git a/tool/warnings-clang.sh b/tool/warnings-clang.sh new file mode 100644 index 00000000..51084f31 --- /dev/null +++ b/tool/warnings-clang.sh @@ -0,0 +1,13 @@ +#/bin/sh +# +# Run this script in a directory with a working makefile to check for +# compiler warnings in SQLite. +# +rm -f sqlite3.c +make sqlite3.c +echo '************* FTS4 and RTREE ****************' +scan-build gcc -c -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ + -DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:' +echo '********** ENABLE_STAT3. THREADSAFE=0 *******' +scan-build gcc -c -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \ + -DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:' diff --git a/tool/warnings.sh b/tool/warnings.sh index e1fa2b2d..78cfb55d 100644 --- a/tool/warnings.sh +++ b/tool/warnings.sh @@ -3,12 +3,17 @@ # Run this script in a directory with a working makefile to check for # compiler warnings in SQLite. # -make sqlite3.c +rm -f sqlite3.c +make sqlite3.c-debug echo '********** No optimizations. Includes FTS4 and RTREE *********' gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ sqlite3.c -echo '********** Optimized -O3. Includes FTS4 and RTREE *********' +echo '********** No optimizations. ENABLE_STAT3. THREADSAFE=0 *******' +gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ + -ansi -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \ + sqlite3.c +echo '********** Optimized -O3. Includes FTS4 and RTREE ************' gcc -O3 -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ sqlite3.c