Index: Makefile.msc ================================================================== --- Makefile.msc +++ Makefile.msc @@ -28,10 +28,17 @@ # has no effect if (any) optimizations are enabled. # !IFNDEF USE_RUNTIME_CHECKS USE_RUNTIME_CHECKS = 0 !ENDIF + +# Set this non-0 to create a SQLite amalgamation file that excludes the +# various built-in extensions. +# +!IFNDEF MINIMAL_AMALGAMATION +MINIMAL_AMALGAMATION = 0 +!ENDIF # Set this non-0 to use "stdcall" calling convention for the core library # and shell executable. # !IFNDEF USE_STDCALL @@ -268,16 +275,43 @@ !ELSE SQLITE3EXEPDB = /pdb:sqlite3sh.pdb !ENDIF !ENDIF +# <> +# These are the names of the customized Tcl header files used by various parts +# of this makefile when the stdcall calling convention is in use. It is not +# used for any other purpose. +# +!IFNDEF SQLITETCLH +SQLITETCLH = sqlite_tcl.h +!ENDIF + +!IFNDEF SQLITETCLDECLSH +SQLITETCLDECLSH = sqlite_tclDecls.h +!ENDIF + +# These are the additional targets that the targets that integrate with the +# Tcl library should depend on when compiling, etc. +# +!IFNDEF SQLITE_TCL_DEP +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 +SQLITE_TCL_DEP = $(SQLITETCLDECLSH) $(SQLITETCLH) +!ELSE +SQLITE_TCL_DEP = +!ENDIF +!ENDIF +# <> + # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS +!IF $(MINIMAL_AMALGAMATION)==0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 +!ENDIF OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF # Should the session extension be enabled? If so, add compilation options # to enable it. @@ -469,24 +503,36 @@ # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" -CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall -SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall +# <> +TEST_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl +# <> !ELSE !IFNDEF PLATFORM -CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall -SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall +# <> +TEST_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl +# <> !ELSE CORE_CCONV_OPTS = SHELL_CCONV_OPTS = +# <> +TEST_CCONV_OPTS = +# <> !ENDIF !ENDIF !ELSE CORE_CCONV_OPTS = SHELL_CCONV_OPTS = +# <> +TEST_CCONV_OPTS = +# <> !ENDIF # These are additional compiler options used for the core library. # !IFNDEF CORE_COMPILE_OPTS @@ -635,15 +681,38 @@ # The mksqlite3c.tcl script accepts some options on the command # line. When compiling with debugging enabled, some of these # options are necessary in order to allow debugging symbols to # work correctly with Visual Studio when using the amalgamation. # +!IFNDEF MKSQLITE3C_TOOL +!IF $(MINIMAL_AMALGAMATION)!=0 +MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c-noext.tcl +!ELSE +MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl +!ENDIF +!ENDIF + !IFNDEF MKSQLITE3C_ARGS !IF $(DEBUG)>1 MKSQLITE3C_ARGS = --linemacros !ELSE MKSQLITE3C_ARGS = +!ENDIF +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 +MKSQLITE3C_ARGS = $(MKSQLITE3C_ARGS) --useapicall +!ENDIF +!ENDIF + +# The mksqlite3h.tcl script accepts some options on the command line. +# When compiling with stdcall support, some of these options are +# necessary. +# +!IFNDEF MKSQLITE3H_ARGS +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 +MKSQLITE3H_ARGS = --useapicall +!ELSE +MKSQLITE3H_ARGS = !ENDIF !ENDIF # <> # Define -DNDEBUG to compile without debugging (i.e., for production usage) @@ -1243,10 +1312,20 @@ SRC11 = \ keywordhash.h \ opcodes.h \ parse.h \ $(SQLITE3H) + +# Generated Tcl header files +# +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 +SRC12 = \ + $(SQLITETCLH) \ + $(SQLITETCLDECLSH) +!ELSE +SRC12 = +!ENDIF # All source code files. # SRC = $(SRC00) $(SRC01) $(SRC02) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) @@ -1350,11 +1429,11 @@ $(TOP)\src\pager.h \ $(TOP)\src\pcache.h \ parse.h \ $(TOP)\src\pragma.h \ $(SQLITE3H) \ - $(TOP)\src\sqlite3ext.h \ + sqlite3ext.h \ $(TOP)\src\sqliteInt.h \ $(TOP)\src\sqliteLimit.h \ $(TOP)\src\vdbe.h \ $(TOP)\src\vdbeInt.h \ $(TOP)\src\vxworks.h \ @@ -1508,11 +1587,11 @@ # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # -.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c +.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c $(SQLITE_TCL_DEP) -rmdir /Q/S tsrc 2>NUL -mkdir tsrc for %i in ($(SRC00)) do copy /Y %i tsrc for %i in ($(SRC01)) do copy /Y %i tsrc for %i in ($(SRC02)) do copy /Y %i tsrc @@ -1523,19 +1602,20 @@ for %i in ($(SRC07)) do copy /Y %i tsrc for %i in ($(SRC08)) do copy /Y %i tsrc for %i in ($(SRC09)) do copy /Y %i tsrc for %i in ($(SRC10)) do copy /Y %i tsrc for %i in ($(SRC11)) do copy /Y %i tsrc + for %i in ($(SRC12)) do copy /Y %i tsrc copy /Y fts5.c tsrc copy /Y fts5.h tsrc del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source -sqlite3.c: .target_source sqlite3ext.h $(TOP)\tool\mksqlite3c.tcl - $(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl $(MKSQLITE3C_ARGS) +sqlite3.c: .target_source sqlite3ext.h $(MKSQLITE3C_TOOL) + $(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS) copy tsrc\shell.c . copy $(TOP)\ext\session\sqlite3session.h . sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl @@ -1804,14 +1884,14 @@ $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\wherecode.c whereexpr.lo: $(TOP)\src\whereexpr.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\whereexpr.c -tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) +tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP) $(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c -tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) +tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP) $(LTCOMPILE) $(NO_WARN) -DTCLSH=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS) $(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS) @@ -1833,14 +1913,20 @@ .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) parse.y move parse.h parse.h.temp $(TCLSH_CMD) $(TOP)\tool\addopcodes.tcl parse.h.temp > parse.h $(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION - $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) + $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS) sqlite3ext.h: .target_source - copy tsrc\sqlite3ext.h . +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 + type tsrc\sqlite3ext.h | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*\)" "(SQLITE_CALLBACK *)" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*" "(SQLITE_APICALL *" > sqlite3ext.h + copy /Y sqlite3ext.h tsrc\sqlite3ext.h +!ELSE + copy /Y tsrc\sqlite3ext.h sqlite3ext.h +!ENDIF mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c $(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) \ $(TOP)\tool\mkkeywordhash.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS) @@ -1969,20 +2055,41 @@ TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024 +TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS) TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C) !IF $(USE_AMALGAMATION)==0 TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) !ELSE TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC1) !ENDIF -testfixture.exe: $(TESTFIXTURE_SRC) $(SQLITE3H) $(LIBRESOBJS) $(HDR) +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 +sqlite_tclDecls.h: + echo #ifndef SQLITE_TCLAPI > $(SQLITETCLDECLSH) + echo # define SQLITE_TCLAPI >> $(SQLITETCLDECLSH) + echo #endif >> $(SQLITETCLDECLSH) + type "$(TCLINCDIR)\tclDecls.h" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "^(EXTERN(?: CONST\d+?)?\s+?[^\(]*?\s+?)Tcl_" "\1 SQLITE_TCLAPI Tcl_" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "^(EXTERN\s+?(?:void|VOID)\s+?)TclFreeObj" "\1 SQLITE_TCLAPI TclFreeObj" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*tcl_" "(SQLITE_TCLAPI *tcl_" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*tclFreeObj" "(SQLITE_TCLAPI *tclFreeObj" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*" "(SQLITE_TCLAPI *" >> $(SQLITETCLDECLSH) + +sqlite_tcl.h: + type "$(TCLINCDIR)\tcl.h" | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact tclDecls.h sqlite_tclDecls.h \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "typedef (.*?)\(Tcl_" "typedef \1 (SQLITE_TCLAPI Tcl_" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "void (*freeProc)" "void (SQLITE_TCLAPI *freeProc)" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "Tcl_HashEntry *(*findProc)" "Tcl_HashEntry *(SQLITE_TCLAPI *findProc)" \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "Tcl_HashEntry *(*createProc)" "Tcl_HashEntry *(SQLITE_TCLAPI *createProc)" >> $(SQLITETCLH) +!ENDIF + +testfixture.exe: $(TESTFIXTURE_SRC) $(SQLITE3H) $(LIBRESOBJS) $(HDR) $(SQLITE_TCL_DEP) $(LTLINK) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \ -DBUILD_sqlite -I$(TCLINCDIR) \ $(TESTFIXTURE_SRC) \ /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) @@ -2027,11 +2134,11 @@ smoketest: $(TESTPROGS) @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\main.test $(TESTOPTS) -sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl +sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(SQLITE_TCL_DEP) echo #define TCLSH 2 > $@ echo #define SQLITE_ENABLE_DBSTAT_VTAB 1 >> $@ copy $@ + $(SQLITE3C) + $(TOP)\src\tclsqlite.c $@ echo static const char *tclsh_main_loop(void){ >> $@ echo static const char *zMainloop = >> $@ @@ -2107,11 +2214,11 @@ del /Q notasharedlib.* 2>NUL -rmdir /Q/S .deps 2>NUL -rmdir /Q/S .libs 2>NUL -rmdir /Q/S tsrc 2>NUL del /Q .target_source 2>NUL - del /Q tclsqlite3.exe 2>NUL + del /Q tclsqlite3.exe $(SQLITETCLH) $(SQLITETCLDECLSH) 2>NUL del /Q testloadext.dll 2>NUL del /Q testfixture.exe test.db 2>NUL del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe 2>NUL del /Q changeset.exe 2>NUL del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -3.15.0 +3.14.2 Index: autoconf/Makefile.msc ================================================================== --- autoconf/Makefile.msc +++ autoconf/Makefile.msc @@ -28,10 +28,17 @@ # has no effect if (any) optimizations are enabled. # !IFNDEF USE_RUNTIME_CHECKS USE_RUNTIME_CHECKS = 0 !ENDIF + +# Set this non-0 to create a SQLite amalgamation file that excludes the +# various built-in extensions. +# +!IFNDEF MINIMAL_AMALGAMATION +MINIMAL_AMALGAMATION = 0 +!ENDIF # Set this non-0 to use "stdcall" calling convention for the core library # and shell executable. # !IFNDEF USE_STDCALL @@ -252,17 +259,20 @@ SQLITE3EXEPDB = !ELSE SQLITE3EXEPDB = /pdb:sqlite3sh.pdb !ENDIF !ENDIF + # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS +!IF $(MINIMAL_AMALGAMATION)==0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 +!ENDIF OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF # Should the session extension be enabled? If so, add compilation options # to enable it. @@ -454,16 +464,16 @@ # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" -CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall -SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall !ELSE !IFNDEF PLATFORM -CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall -SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall !ELSE CORE_CCONV_OPTS = SHELL_CCONV_OPTS = !ENDIF !ENDIF Index: configure ================================================================== --- configure +++ configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for sqlite 3.15.0. +# Generated by GNU Autoconf 2.69 for sqlite 3.14.2. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # @@ -724,12 +724,12 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.15.0' -PACKAGE_STRING='sqlite 3.15.0' +PACKAGE_VERSION='3.14.2' +PACKAGE_STRING='sqlite 3.14.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ @@ -1461,11 +1461,11 @@ # 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.15.0 to adapt to many kinds of systems. +\`configure' configures sqlite 3.14.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. @@ -1526,11 +1526,11 @@ _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.15.0:";; + short | recursive ) echo "Configuration of sqlite 3.14.2:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options @@ -1650,11 +1650,11 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.15.0 +sqlite configure 3.14.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -2069,11 +2069,11 @@ } # 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.15.0, which was +It was created by sqlite $as_me 3.14.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF @@ -12149,11 +12149,11 @@ 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.15.0, which was +This file was extended by sqlite $as_me 3.14.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS @@ -12215,11 +12215,11 @@ _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.15.0 +sqlite config.status 3.14.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation Index: ext/fts5/fts5Int.h ================================================================== --- ext/fts5/fts5Int.h +++ ext/fts5/fts5Int.h @@ -735,11 +735,10 @@ void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); -Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*); void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); /* ** End of interface to code in fts5_expr.c. Index: ext/fts5/fts5_aux.c ================================================================== --- ext/fts5/fts5_aux.c +++ ext/fts5/fts5_aux.c @@ -187,11 +187,11 @@ } if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); p->iOff = iEndOff; - if( iPos>=p->iter.iStart && iPositer.iEnd ){ + if( iPositer.iEnd ){ fts5HighlightAppend(&rc, p, p->zClose, -1); } } return rc; @@ -244,119 +244,10 @@ } /* ** End of highlight() implementation. **************************************************************************/ -/* -** Context object passed to the fts5SentenceFinderCb() function. -*/ -typedef struct Fts5SFinder Fts5SFinder; -struct Fts5SFinder { - int iPos; /* Current token position */ - int nFirstAlloc; /* Allocated size of aFirst[] */ - int nFirst; /* Number of entries in aFirst[] */ - int *aFirst; /* Array of first token in each sentence */ - const char *zDoc; /* Document being tokenized */ -}; - -/* -** Add an entry to the Fts5SFinder.aFirst[] array. Grow the array if -** necessary. Return SQLITE_OK if successful, or SQLITE_NOMEM if an -** error occurs. -*/ -static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){ - if( p->nFirstAlloc==p->nFirst ){ - int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64; - int *aNew; - - aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int)); - if( aNew==0 ) return SQLITE_NOMEM; - p->aFirst = aNew; - p->nFirstAlloc = nNew; - } - p->aFirst[p->nFirst++] = iAdd; - return SQLITE_OK; -} - -/* -** This function is an xTokenize() callback used by the auxiliary snippet() -** function. Its job is to identify tokens that are the first in a sentence. -** For each such token, an entry is added to the SFinder.aFirst[] array. -*/ -static int fts5SentenceFinderCb( - void *pContext, /* Pointer to HighlightContext object */ - int tflags, /* Mask of FTS5_TOKEN_* flags */ - const char *pToken, /* Buffer containing token */ - int nToken, /* Size of token in bytes */ - int iStartOff, /* Start offset of token */ - int iEndOff /* End offset of token */ -){ - int rc = SQLITE_OK; - - if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ - Fts5SFinder *p = (Fts5SFinder*)pContext; - if( p->iPos>0 ){ - int i; - char c = 0; - for(i=iStartOff-1; i>=0; i--){ - c = p->zDoc[i]; - if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) break; - } - if( i!=iStartOff-1 && (c=='.' || c==':') ){ - rc = fts5SentenceFinderAdd(p, p->iPos); - } - }else{ - rc = fts5SentenceFinderAdd(p, 0); - } - p->iPos++; - } - return rc; -} - -static int fts5SnippetScore( - const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ - Fts5Context *pFts, /* First arg to pass to pApi functions */ - int nDocsize, /* Size of column in tokens */ - unsigned char *aSeen, /* Array with one element per query phrase */ - int iCol, /* Column to score */ - int iPos, /* Starting offset to score */ - int nToken, /* Max tokens per snippet */ - int *pnScore, /* OUT: Score */ - int *piPos /* OUT: Adjusted offset */ -){ - int rc; - int i; - int ip = 0; - int ic = 0; - int iOff = 0; - int iFirst = -1; - int nInst; - int nScore = 0; - int iLast = 0; - - rc = pApi->xInstCount(pFts, &nInst); - for(i=0; ixInst(pFts, i, &ip, &ic, &iOff); - if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){ - nScore += (aSeen[ip] ? 1 : 1000); - aSeen[ip] = 1; - if( iFirst<0 ) iFirst = iOff; - iLast = iOff + pApi->xPhraseSize(pFts, ip); - } - } - - *pnScore = nScore; - if( piPos ){ - int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2; - if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken; - if( iAdj<0 ) iAdj = 0; - *piPos = iAdj; - } - - return rc; -} - /* ** Implementation of snippet() function. */ static void fts5SnippetFunction( const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ @@ -374,141 +265,110 @@ int i; /* Used to iterate through instances */ int nPhrase; /* Number of phrases in query */ unsigned char *aSeen; /* Array of "seen instance" flags */ int iBestCol; /* Column containing best snippet */ int iBestStart = 0; /* First token of best snippet */ + int iBestLast; /* Last token of best snippet */ int nBestScore = 0; /* Score of best snippet */ int nColSize = 0; /* Total size of iBestCol in tokens */ - Fts5SFinder sFinder; /* Used to find the beginnings of sentences */ - int nCol; if( nVal!=5 ){ const char *zErr = "wrong number of arguments to function snippet()"; sqlite3_result_error(pCtx, zErr, -1); return; } - nCol = pApi->xColumnCount(pFts); memset(&ctx, 0, sizeof(HighlightContext)); iCol = sqlite3_value_int(apVal[0]); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); zEllips = (const char*)sqlite3_value_text(apVal[3]); nToken = sqlite3_value_int(apVal[4]); + iBestLast = nToken-1; iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); aSeen = sqlite3_malloc(nPhrase); if( aSeen==0 ){ rc = SQLITE_NOMEM; } - if( rc==SQLITE_OK ){ - rc = pApi->xInstCount(pFts, &nInst); - } - - memset(&sFinder, 0, sizeof(Fts5SFinder)); - for(i=0; ixColumnText(pFts, i, &sFinder.zDoc, &nDoc); - if( rc!=SQLITE_OK ) break; - rc = pApi->xTokenize(pFts, - sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb - ); - if( rc!=SQLITE_OK ) break; - rc = pApi->xColumnSize(pFts, i, &nDocsize); - if( rc!=SQLITE_OK ) break; - - for(ii=0; rc==SQLITE_OK && iixInst(pFts, ii, &ip, &ic, &io); - if( ic!=i || rc!=SQLITE_OK ) continue; - memset(aSeen, 0, nPhrase); - rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, - io, nToken, &nScore, &iAdj - ); - if( rc==SQLITE_OK && nScore>nBestScore ){ - nBestScore = nScore; - iBestCol = i; - iBestStart = iAdj; - nColSize = nDocsize; - } - - if( rc==SQLITE_OK && sFinder.nFirst && nDocsize>nToken ){ - for(jj=0; jj<(sFinder.nFirst-1); jj++){ - if( sFinder.aFirst[jj+1]>io ) break; - } - - if( sFinder.aFirst[jj]nBestScore ){ - nBestScore = nScore; - iBestCol = i; - iBestStart = sFinder.aFirst[jj]; - nColSize = nDocsize; - } - } - } - } - } - } - - if( rc==SQLITE_OK ){ - rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn); - } - if( rc==SQLITE_OK && nColSize==0 ){ - rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); - } - if( ctx.zIn ){ - if( rc==SQLITE_OK ){ - rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); - } + + if( rc==SQLITE_OK ){ + rc = pApi->xInstCount(pFts, &nInst); + } + for(i=0; rc==SQLITE_OK && ixInst(pFts, i, &ip, &iSnippetCol, &iStart); + if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){ + int nScore = 1000; + int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip); + int j; + aSeen[ip] = 1; + + for(j=i+1; rc==SQLITE_OK && jxInst(pFts, j, &ip, &ic, &io); + iFinal = io + pApi->xPhraseSize(pFts, ip) - 1; + if( rc==SQLITE_OK && ic==iSnippetCol && iLastiLast ) iLast = iFinal; + } + } + + if( rc==SQLITE_OK && nScore>nBestScore ){ + iBestCol = iSnippetCol; + iBestStart = iStart; + iBestLast = iLast; + nBestScore = nScore; + } + } + } + + if( rc==SQLITE_OK ){ + rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); + } + if( rc==SQLITE_OK ){ + rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn); + } + if( ctx.zIn ){ + if( rc==SQLITE_OK ){ + rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); + } + + if( (iBestStart+nToken-1)>iBestLast ){ + iBestStart -= (iBestStart+nToken-1-iBestLast) / 2; + } + if( iBestStart+nToken>nColSize ){ + iBestStart = nColSize - nToken; + } + if( iBestStart<0 ) iBestStart = 0; ctx.iRangeStart = iBestStart; ctx.iRangeEnd = iBestStart + nToken - 1; if( iBestStart>0 ){ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } - - /* Advance iterator ctx.iter so that it points to the first coalesced - ** phrase instance at or following position iBestStart. */ - while( ctx.iter.iStart>=0 && ctx.iter.iStartxTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } if( ctx.iRangeEnd>=(nColSize-1) ){ fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); }else{ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } - } - if( rc==SQLITE_OK ){ - sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); - }else{ - sqlite3_result_error_code(pCtx, rc); - } - sqlite3_free(ctx.zOut); - sqlite3_free(aSeen); - sqlite3_free(sFinder.aFirst); + + if( rc==SQLITE_OK ){ + sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); + }else{ + sqlite3_result_error_code(pCtx, rc); + } + sqlite3_free(ctx.zOut); + } + sqlite3_free(aSeen); } /************************************************************************/ /* Index: ext/fts5/fts5_expr.c ================================================================== --- ext/fts5/fts5_expr.c +++ ext/fts5/fts5_expr.c @@ -165,11 +165,10 @@ case '}': tok = FTS5_RCP; break; case ':': tok = FTS5_COLON; break; case ',': tok = FTS5_COMMA; break; case '+': tok = FTS5_PLUS; break; case '*': tok = FTS5_STAR; break; - case '-': tok = FTS5_MINUS; break; case '\0': tok = FTS5_EOF; break; case '"': { const char *z2; tok = FTS5_STRING; @@ -1657,11 +1656,11 @@ sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ - int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); + int nByte = sizeof(Fts5Colset) + pColsetOrig->nCol * sizeof(int); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ memcpy(pColset, pColsetOrig, nByte); } pNew->pRoot->pNear->pColset = pColset; @@ -1792,38 +1791,10 @@ } return pNew; } -/* -** Allocate and return an Fts5Colset object specifying the inverse of -** the colset passed as the second argument. Free the colset passed -** as the second argument before returning. -*/ -Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){ - Fts5Colset *pRet; - int nCol = pParse->pConfig->nCol; - - pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, - sizeof(Fts5Colset) + sizeof(int)*nCol - ); - if( pRet ){ - int i; - int iOld = 0; - for(i=0; i=p->nCol || p->aiCol[iOld]!=i ){ - pRet->aiCol[pRet->nCol++] = i; - }else{ - iOld++; - } - } - } - - sqlite3_free(p); - return pRet; -} - Fts5Colset *sqlite3Fts5ParseColset( Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ Fts5Colset *pColset, /* Existing colset object */ Fts5Token *p ){ Index: ext/fts5/fts5_index.c ================================================================== --- ext/fts5/fts5_index.c +++ ext/fts5/fts5_index.c @@ -699,31 +699,20 @@ } assert( (pRet==0)==(p->rc!=SQLITE_OK) ); return pRet; } + /* ** Release a reference to data record returned by an earlier call to ** fts5DataRead(). */ static void fts5DataRelease(Fts5Data *pData){ sqlite3_free(pData); } -static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ - Fts5Data *pRet = fts5DataRead(p, iRowid); - if( pRet ){ - if( pRet->szLeaf>pRet->nn ){ - p->rc = FTS5_CORRUPT; - fts5DataRelease(pRet); - pRet = 0; - } - } - return pRet; -} - static int fts5IndexPrepareStmt( Fts5Index *p, sqlite3_stmt **ppStmt, char *zSql ){ @@ -1528,11 +1517,11 @@ pIter->iLeafPgno++; if( pIter->pNextLeaf ){ pIter->pLeaf = pIter->pNextLeaf; pIter->pNextLeaf = 0; }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){ - pIter->pLeaf = fts5LeafRead(p, + pIter->pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno) ); }else{ pIter->pLeaf = 0; } @@ -2031,12 +2020,13 @@ pIter->iLeafOffset = iOff; if( pLeaf->nn>pLeaf->szLeaf ){ pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist - ); + ); } + } else if( pLeaf->nn>pLeaf->szLeaf ){ pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( &pLeaf->p[pLeaf->szLeaf], iOff ); @@ -2277,15 +2267,10 @@ iPgidx += fts5GetVarint32(&a[iPgidx], nKeep); iTermOff += nKeep; iOff = iTermOff; - if( iOff>=n ){ - p->rc = FTS5_CORRUPT; - return; - } - /* Read the nKeep field of the next term. */ fts5FastGetVarint32(a, iOff, nKeep); } search_failed: @@ -3208,19 +3193,10 @@ fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); pIter->base.pData = pIter->poslist.p; } } -/* -** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match -** against no columns at all). -*/ -static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){ - UNUSED_PARAM(pSeg); - pIter->base.nData = 0; -} - /* ** xSetOutputs callback used by detail=col when there is a column filter ** and there are 100 or more columns. Also called as a fallback from ** fts5IterSetOutputs_Col100 if the column-list spans more than one page. */ @@ -3322,14 +3298,10 @@ else if( pIter->pColset==0 ){ pIter->xSetOutputs = fts5IterSetOutputs_Nocolset; } - else if( pIter->pColset->nCol==0 ){ - pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset; - } - else if( pConfig->eDetail==FTS5_DETAIL_FULL ){ pIter->xSetOutputs = fts5IterSetOutputs_Full; } else{ Index: ext/fts5/fts5parse.y ================================================================== --- ext/fts5/fts5parse.y +++ ext/fts5/fts5parse.y @@ -118,27 +118,21 @@ %type colset {Fts5Colset*} %destructor colset { sqlite3_free($$); } %type colsetlist {Fts5Colset*} %destructor colsetlist { sqlite3_free($$); } -colset(A) ::= MINUS LCP colsetlist(X) RCP. { - A = sqlite3Fts5ParseColsetInvert(pParse, X); -} colset(A) ::= LCP colsetlist(X) RCP. { A = X; } colset(A) ::= STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); } -colset(A) ::= MINUS STRING(X). { - A = sqlite3Fts5ParseColset(pParse, 0, &X); - A = sqlite3Fts5ParseColsetInvert(pParse, A); -} colsetlist(A) ::= colsetlist(Y) STRING(X). { A = sqlite3Fts5ParseColset(pParse, Y, &X); } colsetlist(A) ::= STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); } + %type nearset {Fts5ExprNearset*} %type nearphrases {Fts5ExprNearset*} %destructor nearset { sqlite3Fts5ParseNearsetFree($$); } %destructor nearphrases { sqlite3Fts5ParseNearsetFree($$); } Index: ext/fts5/test/fts5af.test ================================================================== --- ext/fts5/test/fts5af.test +++ ext/fts5/test/fts5af.test @@ -70,60 +70,46 @@ 2.1 {X o o o o o o o} {[X] o o o o o o...} 2.2 {o X o o o o o o} {o [X] o o o o o...} 2.3 {o o X o o o o o} {o o [X] o o o o...} 2.4 {o o o X o o o o} {o o o [X] o o o...} - 2.5 {o o o o X o o o} {o o o o [X] o o...} - 2.6 {o o o o o X o o} {o o o o o [X] o...} - 2.7 {o o o o o o X o} {o o o o o o [X]...} + 2.5 {o o o o X o o o} {...o o o [X] o o o} + 2.6 {o o o o o X o o} {...o o o o [X] o o} + 2.7 {o o o o o o X o} {...o o o o o [X] o} 2.8 {o o o o o o o X} {...o o o o o o [X]} - - 2.9 {o o o o o o o X o} {...o o o o o [X] o} - 2.10 {o o o o o o o X o o} {...o o o o [X] o o} - 2.11 {o o o o o o o X o o o} {...o o o [X] o o o} - 2.12 {o o o o o o o X o o o o} {...o o o [X] o o o...} - 3.1 {X o o o o o o o o} {[X] o o o o o o...} 3.2 {o X o o o o o o o} {o [X] o o o o o...} 3.3 {o o X o o o o o o} {o o [X] o o o o...} 3.4 {o o o X o o o o o} {o o o [X] o o o...} - - 3.5 {o o o o o o o X o o o o} {...o o o [X] o o o...} - 3.6 {o o o o o o o o X o o o} {...o o o [X] o o o} - 3.7 {o o o o o o o o o X o o} {...o o o o [X] o o} - 3.8 {o o o o o o o o o o X o} {...o o o o o [X] o} - 3.9 {o o o o o o o o o o o X} {...o o o o o o [X]} + 3.5 {o o o o X o o o o} {...o o o [X] o o o...} + 3.6 {o o o o o X o o o} {...o o o [X] o o o} + 3.7 {o o o o o o X o o} {...o o o o [X] o o} + 3.8 {o o o o o o o X o} {...o o o o o [X] o} + 3.9 {o o o o o o o o X} {...o o o o o o [X]} 4.1 {X o o o o o X o o} {[X] o o o o o [X]...} - 4.2 {o o o o o o o X o o o o o X o} {...[X] o o o o o [X]...} - 4.3 {o o o o o o o o X o o o o o X} {...[X] o o o o o [X]} + 4.2 {o X o o o o o X o} {...[X] o o o o o [X]...} + 4.3 {o o X o o o o o X} {...[X] o o o o o [X]} 5.1 {X o o o o X o o o} {[X] o o o o [X] o...} - 5.2 {o o o o o o o X o o o o X o o} {...[X] o o o o [X] o...} - 5.3 {o o o o o o o o X o o o o X o} {...[X] o o o o [X] o} - 5.4 {o o o o o o o o o X o o o o X} {...o [X] o o o o [X]} + 5.2 {o X o o o o X o o} {...[X] o o o o [X] o...} + 5.3 {o o X o o o o X o} {...[X] o o o o [X] o} + 5.4 {o o o X o o o o X} {...o [X] o o o o [X]} 6.1 {X o o o X o o o} {[X] o o o [X] o o...} 6.2 {o X o o o X o o o} {o [X] o o o [X] o...} - 6.3 {o o o o o o o X o o o X o o} {...o [X] o o o [X] o...} - 6.4 {o o o o o o o o X o o o X o} {...o [X] o o o [X] o} - 6.5 {o o o o o o o o o X o o o X} {...o o [X] o o o [X]} + 6.3 {o o X o o o X o o} {...o [X] o o o [X] o...} + 6.4 {o o o X o o o X o} {...o [X] o o o [X] o} + 6.5 {o o o o X o o o X} {...o o [X] o o o [X]} 7.1 {X o o X o o o o o} {[X] o o [X] o o o...} 7.2 {o X o o X o o o o} {o [X] o o [X] o o...} - 7.3 {o o o o o o o X o o X o o o} {...o [X] o o [X] o o...} - 7.4 {o o o o o o o o X o o X o o} {...o [X] o o [X] o o} - 7.5 {o o o o o o o o o X o o X o} {...o o [X] o o [X] o} - 7.6 {o o o o o o o o o o X o o X} {...o o o [X] o o [X]} - - 8.1 {o o o o o o o o o X o o o o o o o o o o o o o o o o X X X o o o} - {...o o [X] [X] [X] o o...} - 8.2 {o o o o o o o. o o X o o o o o o o o o o o o o o o o X X X o o o} - {...o o [X] o o o o...} - 8.3 {o o o o X o o o o o o o o o o o o o o o o o o o o o X X X o o o} - {o o o o [X] o o...} + 7.3 {o o X o o X o o o} {...o [X] o o [X] o o...} + 7.4 {o o o X o o X o o} {...o [X] o o [X] o o} + 7.5 {o o o o X o o X o} {...o o [X] o o [X] o} + 7.6 {o o o o o X o o X} {...o o o [X] o o [X]} } { do_snippet_test 1.$tn $doc X $res } if {[detail_is_full]} { @@ -136,46 +122,27 @@ 1.6 {o o o o o X Y} {o o o o o [X Y]} 2.1 {X Y o o o o o o} {[X Y] o o o o o...} 2.2 {o X Y o o o o o} {o [X Y] o o o o...} 2.3 {o o X Y o o o o} {o o [X Y] o o o...} - 2.4 {o o o o o o o X Y o o o} {...o o [X Y] o o o} - 2.5 {o o o o o o o o X Y o o} {...o o o [X Y] o o} - 2.6 {o o o o o o o o o X Y o} {...o o o o [X Y] o} - 2.7 {o o o o o o o o o o X Y} {...o o o o o [X Y]} + 2.4 {o o o X Y o o o} {...o o [X Y] o o o} + 2.5 {o o o o X Y o o} {...o o o [X Y] o o} + 2.6 {o o o o o X Y o} {...o o o o [X Y] o} + 2.7 {o o o o o o X Y} {...o o o o o [X Y]} 3.1 {X Y o o o o o o o} {[X Y] o o o o o...} 3.2 {o X Y o o o o o o} {o [X Y] o o o o...} 3.3 {o o X Y o o o o o} {o o [X Y] o o o...} - 3.4 {o o o o o o o X Y o o o o} {...o o [X Y] o o o...} - 3.5 {o o o o o o o o X Y o o o} {...o o [X Y] o o o} - 3.6 {o o o o o o o o o X Y o o} {...o o o [X Y] o o} - 3.7 {o o o o o o o o o o X Y o} {...o o o o [X Y] o} - 3.8 {o o o o o o o o o o o X Y} {...o o o o o [X Y]} + 3.4 {o o o X Y o o o o} {...o o [X Y] o o o...} + 3.5 {o o o o X Y o o o} {...o o [X Y] o o o} + 3.6 {o o o o o X Y o o} {...o o o [X Y] o o} + 3.7 {o o o o o o X Y o} {...o o o o [X Y] o} + 3.8 {o o o o o o o X Y} {...o o o o o [X Y]} } { do_snippet_test 2.$tn $doc "X + Y" $res } } -do_execsql_test 4.0 { - CREATE VIRTUAL TABLE x1 USING fts5(a, b); - INSERT INTO x1 VALUES('xyz', '1 2 3 4 5 6 7 8 9 10 11 12 13'); - SELECT snippet(x1, 1, '[', ']', '...', 5) FROM x1('xyz'); -} { - {1 2 3 4 5...} -} - -do_execsql_test 5.0 { - CREATE VIRTUAL TABLE p1 USING fts5(a, b); - INSERT INTO p1 VALUES( - 'x a a a a a a a a a a', - 'a a a a a a a a a a a a a a a a a a a x' - ); -} -do_execsql_test 5.1 { - SELECT snippet(p1, 0, '[', ']', '...', 6) FROM p1('x'); -} {{[x] a a a a a...}} - } ;# foreach_detail_mode finish_test DELETED ext/fts5/test/fts5colset.test Index: ext/fts5/test/fts5colset.test ================================================================== --- ext/fts5/test/fts5colset.test +++ /dev/null @@ -1,59 +0,0 @@ -# 2016 August 10 -# -# The author disclaims copyright to this source code. In place of -# a legal notice, here is a blessing: -# -# May you do good and not evil. -# May you find forgiveness for yourself and forgive others. -# May you share freely, never taking more than you give. -# -#************************************************************************* -# This file implements regression tests for SQLite library. The -# focus of this script is testing the FTS5 module. -# - -source [file join [file dirname [info script]] fts5_common.tcl] -set testprefix fts5colset - -# If SQLITE_ENABLE_FTS5 is not defined, omit this file. -ifcapable !fts5 { - finish_test - return -} - -foreach_detail_mode $::testprefix { - if {[detail_is_none]} continue - - do_execsql_test 1.0 { - CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, d, detail=%DETAIL%); - INSERT INTO t1 VALUES('a', 'b', 'c', 'd'); -- 1 - INSERT INTO t1 VALUES('d', 'a', 'b', 'c'); -- 2 - INSERT INTO t1 VALUES('c', 'd', 'a', 'b'); -- 3 - INSERT INTO t1 VALUES('b', 'c', 'd', 'a'); -- 4 - } - - foreach {tn q res} { - 1 "a" {1 2 3 4} - 2 "{a} : a" {1} - 3 "-{a} : a" {2 3 4} - 4 "- {a c} : a" {2 4} - 5 " - {d d c} : a" {1 2} - 6 "- {d c b a} : a" {} - 7 "-{\"a\"} : b" {1 2 3} - 8 "- c : a" {1 2 4} - 9 "-c : a" {1 2 4} - 10 "-\"c\" : a" {1 2 4} - } { - breakpoint - do_execsql_test 1.$tn { - SELECT rowid FROM t1($q) - } $res - } - - -} - - -finish_test - - Index: ext/fts5/test/fts5corrupt2.test ================================================================== --- ext/fts5/test/fts5corrupt2.test +++ ext/fts5/test/fts5corrupt2.test @@ -35,11 +35,11 @@ WITH ii(i) AS (SELECT 1 UNION SELECT i+1 FROM ii WHERE i<100) INSERT INTO t1 SELECT rnddoc(10) FROM ii; } set mask [expr 31 << 31] -if 0 { +if 1 { # Test 1: # # For each page in the t1_data table, open a transaction and DELETE # the t1_data entry. Then run: @@ -80,12 +80,10 @@ do_execsql_test 1.$tno.$tn.3.$rowid { ROLLBACK; INSERT INTO t1(t1) VALUES('integrity-check'); } {} } -} - } # Using the same database as the 1.* tests. # # Run N-1 tests, where N is the number of bytes in the rightmost leaf page @@ -210,10 +208,12 @@ execsql ROLLBACK } # do_test 4.$tn.x { expr $nCorrupt>0 } 1 +} + } set doc [string repeat "A B C " 1000] do_execsql_test 5.0 { CREATE VIRTUAL TABLE x5 USING fts5(tt); Index: ext/fts5/test/fts5unicode2.test ================================================================== --- ext/fts5/test/fts5unicode2.test +++ ext/fts5/test/fts5unicode2.test @@ -158,16 +158,16 @@ 3 "ROW" { ...returns the value of y on the same [row] that contains the maximum x value. } 4 "rollback" { - Pending statements no longer block [ROLLBACK]. Instead, the pending - statement will return SQLITE_ABORT upon... + ...[ROLLBACK]. Instead, the pending statement + will return SQLITE_ABORT upon next access after the [ROLLBACK]. } 5 "rOllback" { - Pending statements no longer block [ROLLBACK]. Instead, the pending - statement will return SQLITE_ABORT upon... + ...[ROLLBACK]. Instead, the pending statement + will return SQLITE_ABORT upon next access after the [ROLLBACK]. } 6 "lang*" { Added support for the FTS4 [languageid] option. } } { Index: ext/rbu/rbudiff.test ================================================================== --- ext/rbu/rbudiff.test +++ ext/rbu/rbudiff.test @@ -138,19 +138,10 @@ INSERT INTO t2 VALUES(1, X'0000000000000000111111111111111122222222222222223333333FFF333333' ); } - 4 { - CREATE TABLE x1(a, b, c, PRIMARY KEY(a, b, c)); - INSERT INTO x1 VALUES('u', 'v', NULL); - INSERT INTO x1 VALUES('x', 'y', 'z'); - INSERT INTO x1 VALUES('a', NULL, 'b'); - } { - INSERT INTO x1 VALUES('a', 'b', 'c'); - } - } { catch { db close } forcedelete test.db test.db2 sqlite3 db test.db @@ -286,9 +277,8 @@ db close db2 close } } - finish_test ADDED ext/rbu/rbuempty.test Index: ext/rbu/rbuempty.test ================================================================== --- /dev/null +++ ext/rbu/rbuempty.test @@ -0,0 +1,77 @@ +# 2022 September 27 +# +# 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. +# +#*********************************************************************** +# + +source [file join [file dirname [info script]] rbu_common.tcl] +set ::testprefix rbuempty + +db close +sqlite3_shutdown +sqlite3_config_uri 1 + +forcedelete rbu.db +sqlite3 db test.db +do_execsql_test 1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + INSERT INTO t1 VALUES(3, 'three'); + + ATTACH 'rbu.db' AS aux; + CREATE TABLE aux.data_t1(a, b, rbu_control); + DETACH aux; +} + +do_test 1.1 { + sqlite3rbu rbu test.db rbu.db + lappend ::v [rbu state] + lappend ::v [rbu bp_progress] + while {[rbu step]=="SQLITE_OK"} { + lappend ::v [rbu state] + lappend ::v [rbu bp_progress] + } + lappend ::v [rbu state] + lappend ::v [rbu bp_progress] + rbu close +} {SQLITE_DONE} + +do_execsql_test 1.2 { + SELECT * FROM t1 +} {1 one 2 two 3 three} + +forcedelete rbu.db +do_execsql_test 1.3 { + ATTACH 'rbu.db' AS aux; + CREATE TABLE aux.data_t1(a, b, rbu_control); + INSERT INTO aux.data_t1 VALUES(4, 'FOUR', 0); + DETACH aux; +} + +do_test 1.4 { + while {1} { + sqlite3rbu rbu test.db rbu.db + lappend ::v [rbu state] + lappend ::v [rbu bp_progress] + set rc [rbu step] + lappend ::v [rbu state] + lappend ::v [rbu bp_progress] + rbu close + if {$rc!="SQLITE_OK"} break + db eval { SELECT * FROM t1 } + db eval { PRAGMA wal_checkpoint = restart } + } +} {} + + + +finish_test + + Index: ext/rbu/rbuprogress.test ================================================================== --- ext/rbu/rbuprogress.test +++ ext/rbu/rbuprogress.test @@ -359,12 +359,10 @@ vtab { CREATE VIRTUAL TABLE t1 USING fts5(a, b, c); } } { - if {$tn=="vtab"} { ifcapable !fts5 break } - foreach {tn2 rbusql r1 r2} { 1 { CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control); INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0); INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0); Index: ext/rbu/rbuvacuum2.test ================================================================== --- ext/rbu/rbuvacuum2.test +++ ext/rbu/rbuvacuum2.test @@ -154,51 +154,9 @@ table t1 t1 2 {CREATE TABLE t1(a, b, c)} view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t1} trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END} } } -} - -#------------------------------------------------------------------------- -# Test that passing a NULL value as the second argument to -# sqlite3rbu_vacuum() causes it to: -# -# * Use -vacuum as the state db, and -# * Set the state db permissions to the same as those on the db file. -# -db close -if {$::tcl_platform(platform)=="unix"} { - forcedelete test.db - - sqlite3 db test.db - do_execsql_test 5.0 { - 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); - } - db close - - foreach {tn perm} { - 1 00755 - 2 00666 - 3 00644 - 4 00444 - } { - forcedelete test.db-vacuum - - do_test 5.$tn.1 { - file attributes test.db -permissions $perm - sqlite3rbu_vacuum rbu test.db - rbu step - } {SQLITE_OK} - - do_test 5.$tn.2 { file exists test.db-vacuum } 1 - do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} $perm - rbu close - } -} - - -finish_test - + +} + +finish_test Index: ext/rbu/sqlite3rbu.c ================================================================== --- ext/rbu/sqlite3rbu.c +++ ext/rbu/sqlite3rbu.c @@ -2332,22 +2332,19 @@ /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ static void rbuOpenDatabase(sqlite3rbu *p){ - assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); - assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); + assert( p->rc==SQLITE_OK ); + assert( p->dbMain==0 && p->dbRbu==0 ); + assert( rbuIsVacuum(p) || p->zTarget!=0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); - if( p->zState==0 ){ - const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); - p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile); - } } /* If using separate RBU and state databases, attach the state database to ** the RBU db handle now. */ if( p->zState ){ @@ -2598,18 +2595,20 @@ p->eStage = RBU_STAGE_CAPTURE; rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0); if( rc2!=SQLITE_INTERNAL ) p->rc = rc2; } - if( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK && p->nFrame>0 ){ p->eStage = RBU_STAGE_CKPT; p->nStep = (pState ? pState->nRow : 0); p->aBuf = rbuMalloc(p, p->pgsz); p->iWalCksum = rbuShmChecksum(p); } - if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){ + if( p->rc==SQLITE_OK + && (p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum)) + ){ p->rc = SQLITE_DONE; p->eStage = RBU_STAGE_DONE; } } @@ -3478,11 +3477,12 @@ const char *zState ){ sqlite3rbu *p; size_t nTarget = zTarget ? strlen(zTarget) : 0; size_t nRbu = strlen(zRbu); - size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1; + size_t nState = zState ? strlen(zState) : 0; + size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1; p = (sqlite3rbu*)sqlite3_malloc64(nByte); if( p ){ RbuState *pState = 0; @@ -3500,11 +3500,12 @@ } p->zRbu = pCsr; memcpy(p->zRbu, zRbu, nRbu+1); pCsr += nRbu+1; if( zState ){ - p->zState = rbuMPrintf(p, "%s", zState); + p->zState = pCsr; + memcpy(p->zState, zState, nState+1); } rbuOpenDatabase(p); } if( p->rc==SQLITE_OK ){ @@ -3610,33 +3611,18 @@ } return p; } -/* -** Allocate and return an RBU handle with all fields zeroed except for the -** error code, which is set to SQLITE_MISUSE. -*/ -static sqlite3rbu *rbuMisuseError(void){ - sqlite3rbu *pRet; - pRet = sqlite3_malloc64(sizeof(sqlite3rbu)); - if( pRet ){ - memset(pRet, 0, sizeof(sqlite3rbu)); - pRet->rc = SQLITE_MISUSE; - } - return pRet; -} - /* ** Open and return a new RBU handle. */ sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ - if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } /* @@ -3644,11 +3630,10 @@ */ sqlite3rbu *sqlite3rbu_vacuum( const char *zTarget, const char *zState ){ - if( zTarget==0 ){ return rbuMisuseError(); } /* TODO: Check that both arguments are non-NULL */ return openRbuHandle(0, zTarget, zState); } /* @@ -3722,11 +3707,10 @@ sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; *pzErrmsg = p->zErrmsg; - sqlite3_free(p->zState); sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; } Index: ext/rbu/sqlite3rbu.h ================================================================== --- ext/rbu/sqlite3rbu.h +++ ext/rbu/sqlite3rbu.h @@ -102,11 +102,11 @@ ** ** Instead of the plain data_ naming scheme, RBU database tables ** may also be named data_, where is any sequence ** of zero or more numeric characters (0-9). This can be significant because ** tables within the RBU database are always processed in order sorted by -** name. By judicious selection of the portion of the names +** name. By judicious selection of the the portion of the names ** of the RBU tables the user can therefore control the order in which they ** are processed. This can be useful, for example, to ensure that "external ** content" FTS4 tables are updated before their underlying content tables. ** ** If the target database table is a virtual table or a table that has no @@ -317,26 +317,20 @@ /* ** Open an RBU handle to perform an RBU vacuum on database file zTarget. ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** -** The second argument to this function identifies a database in which -** to store the state of the RBU vacuum operation if it is suspended. The -** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum -** operation, the state database should either not exist or be empty -** (contain no tables). If an RBU vacuum is suspended by calling +** The second argument to this function, which may not be NULL, identifies +** a database in which to store the state of the RBU vacuum operation if +** it is suspended. The first time sqlite3rbu_vacuum() is called, to start +** an RBU vacuum operation, the state database should either not exist or +** be empty (contain no tables). If an RBU vacuum is suspended by calling ** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has ** returned SQLITE_DONE, the vacuum state is stored in the state database. ** The vacuum can be resumed by calling this function to open a new RBU ** handle specifying the same target and state databases. ** -** If the second argument passed to this function is NULL, then the -** name of the state database is "-vacuum", where -** is the name of the target database file. In this case, on UNIX, if the -** state database is not already present in the file-system, it is created -** with the same permissions as the target db is made. -** ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, ** the next call to sqlite3rbu_vacuum() opens a handle that starts a Index: ext/rbu/test_rbu.c ================================================================== --- ext/rbu/test_rbu.c +++ ext/rbu/test_rbu.c @@ -238,17 +238,17 @@ sqlite3rbu *pRbu = 0; const char *zCmd; const char *zTarget; const char *zStateDb = 0; - if( objc!=3 && objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB ?STATE-DB?"); + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB STATE-DB"); return TCL_ERROR; } zCmd = Tcl_GetString(objv[1]); zTarget = Tcl_GetString(objv[2]); - if( objc==4 ) zStateDb = Tcl_GetString(objv[3]); + zStateDb = Tcl_GetString(objv[3]); pRbu = sqlite3rbu_vacuum(zTarget, zStateDb); Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; Index: ext/rtree/rtree.c ================================================================== --- ext/rtree/rtree.c +++ ext/rtree/rtree.c @@ -1540,11 +1540,11 @@ pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ - RtreeSearchPoint *p; /* Search point for the leaf */ + RtreeSearchPoint *p; /* Search point for the the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); i64 iNode = 0; rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); if( rc==SQLITE_OK && pLeaf!=0 ){ p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); Index: ext/session/session_common.tcl ================================================================== --- ext/session/session_common.tcl +++ ext/session/session_common.tcl @@ -73,13 +73,10 @@ execsql $sql db execsql $sql db2 } proc changeset_from_sql {sql {dbname main}} { - if {$dbname == "main"} { - return [sql_exec_changeset db $sql] - } set rc [catch { sqlite3session S db $dbname db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { S attach $name } Index: ext/session/sqlite3session.h ================================================================== --- ext/session/sqlite3session.h +++ ext/session/sqlite3session.h @@ -725,16 +725,16 @@ void **ppOut /* OUT: Buffer containing output changeset */ ); /* -** CAPI3REF: Changegroup Handle +** Changegroup handle. */ typedef struct sqlite3_changegroup sqlite3_changegroup; /* -** CAPI3REF: Create A New Changegroup Object +** CAPI3REF: Combine two or more changesets into a single changeset. ** ** An sqlite3_changegroup object is used to combine two or more changesets ** (or patchsets) into a single changeset (or patchset). A single changegroup ** object may combine changesets or patchsets, but not both. The output is ** always in the same format as the input. @@ -767,12 +767,10 @@ ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). */ int sqlite3changegroup_new(sqlite3_changegroup **pp); /* -** CAPI3REF: Add A Changeset To A Changegroup -** ** Add all changes within the changeset (or patchset) in buffer pData (size ** nData bytes) to the changegroup. ** ** If the buffer contains a patchset, then all prior calls to this function ** on the same changegroup object must also have specified patchsets. Or, if @@ -844,12 +842,10 @@ ** If no error occurs, SQLITE_OK is returned. */ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* -** CAPI3REF: Obtain A Composite Changeset From A Changegroup -** ** Obtain a buffer containing a changeset (or patchset) representing the ** current contents of the changegroup. If the inputs to the changegroup ** were themselves changesets, the output is a changeset. Or, if the ** inputs were patchsets, the output is also a patchset. ** @@ -874,11 +870,11 @@ int *pnData, /* OUT: Size of output buffer in bytes */ void **ppData /* OUT: Pointer to output buffer */ ); /* -** CAPI3REF: Delete A Changegroup Object +** Delete a changegroup object. */ void sqlite3changegroup_delete(sqlite3_changegroup*); /* ** CAPI3REF: Apply A Changeset To A Database Index: ext/session/test_session.c ================================================================== --- ext/session/test_session.c +++ ext/session/test_session.c @@ -26,111 +26,10 @@ int nStream; /* Maximum chunk size */ unsigned char *aData; /* Pointer to buffer containing data */ int nData; /* Size of buffer aData in bytes */ int iData; /* Bytes of data already read by sessions */ }; - -/* -** Extract an sqlite3* db handle from the object passed as the second -** argument. If successful, set *pDb to point to the db handle and return -** TCL_OK. Otherwise, return TCL_ERROR. -*/ -static int dbHandleFromObj(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **pDb){ - Tcl_CmdInfo info; - if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(pObj), &info) ){ - Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(pObj), 0); - return TCL_ERROR; - } - - *pDb = *(sqlite3 **)info.objClientData; - return TCL_OK; -} - -/************************************************************************* -** The following code is copied byte-for-byte from the sessions module -** documentation. It is used by some of the sessions modules tests to -** ensure that the example in the documentation does actually work. -*/ -/* -** Argument zSql points to a buffer containing an SQL script to execute -** against the database handle passed as the first argument. As well as -** executing the SQL script, this function collects a changeset recording -** all changes made to the "main" database file. Assuming no error occurs, -** output variables (*ppChangeset) and (*pnChangeset) are set to point -** to a buffer containing the changeset and the size of the changeset in -** bytes before returning SQLITE_OK. In this case it is the responsibility -** of the caller to eventually free the changeset blob by passing it to -** the sqlite3_free function. -** -** Or, if an error does occur, return an SQLite error code. The final -** value of (*pChangeset) and (*pnChangeset) are undefined in this case. -*/ -int sql_exec_changeset( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL script to execute */ - int *pnChangeset, /* OUT: Size of changeset blob in bytes */ - void **ppChangeset /* OUT: Pointer to changeset blob */ -){ - sqlite3_session *pSession = 0; - int rc; - - /* Create a new session object */ - rc = sqlite3session_create(db, "main", &pSession); - - /* Configure the session object to record changes to all tables */ - if( rc==SQLITE_OK ) rc = sqlite3session_attach(pSession, NULL); - - /* Execute the SQL script */ - if( rc==SQLITE_OK ) rc = sqlite3_exec(db, zSql, 0, 0, 0); - - /* Collect the changeset */ - if( rc==SQLITE_OK ){ - rc = sqlite3session_changeset(pSession, pnChangeset, ppChangeset); - } - - /* Delete the session object */ - sqlite3session_delete(pSession); - - return rc; -} -/************************************************************************/ - -/* -** Tclcmd: sql_exec_changeset DB SQL -*/ -static int SQLITE_TCLAPI test_sql_exec_changeset( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - const char *zSql; - sqlite3 *db; - void *pChangeset; - int nChangeset; - int rc; - - if( objc!=3 ){ - Tcl_WrongNumArgs(interp, 1, objv, "DB SQL"); - return TCL_ERROR; - } - if( dbHandleFromObj(interp, objv[1], &db) ) return TCL_ERROR; - zSql = (const char*)Tcl_GetString(objv[2]); - - rc = sql_exec_changeset(db, zSql, &nChangeset, &pChangeset); - if( rc!=SQLITE_OK ){ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "error in sql_exec_changeset()", 0); - return TCL_ERROR; - } - - Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pChangeset, nChangeset)); - sqlite3_free(pChangeset); - return TCL_OK; -} - - #define SESSION_STREAM_TCL_VAR "sqlite3session_streams" /* ** Attempt to find the global variable zVar within interpreter interp @@ -1018,29 +917,26 @@ return TCL_OK; } int TestSession_Init(Tcl_Interp *interp){ - struct Cmd { - const char *zCmd; - Tcl_ObjCmdProc *xProc; - } aCmd[] = { - { "sqlite3session", test_sqlite3session }, - { "sqlite3session_foreach", test_sqlite3session_foreach }, - { "sqlite3changeset_invert", test_sqlite3changeset_invert }, - { "sqlite3changeset_concat", test_sqlite3changeset_concat }, - { "sqlite3changeset_apply", test_sqlite3changeset_apply }, - { "sqlite3changeset_apply_replace_all", - test_sqlite3changeset_apply_replace_all }, - { "sql_exec_changeset", test_sql_exec_changeset }, - }; - int i; - - for(i=0; izCmd, p->xProc, 0, 0); - } - + Tcl_CreateObjCommand(interp, "sqlite3session", test_sqlite3session, 0, 0); + Tcl_CreateObjCommand( + interp, "sqlite3session_foreach", test_sqlite3session_foreach, 0, 0 + ); + Tcl_CreateObjCommand( + interp, "sqlite3changeset_invert", test_sqlite3changeset_invert, 0, 0 + ); + Tcl_CreateObjCommand( + interp, "sqlite3changeset_concat", test_sqlite3changeset_concat, 0, 0 + ); + Tcl_CreateObjCommand( + interp, "sqlite3changeset_apply", test_sqlite3changeset_apply, 0, 0 + ); + Tcl_CreateObjCommand( + interp, "sqlite3changeset_apply_replace_all", + test_sqlite3changeset_apply_replace_all, 0, 0 + ); return TCL_OK; } #endif /* SQLITE_TEST && SQLITE_SESSION && SQLITE_PREUPDATE_HOOK */ Index: src/alter.c ================================================================== --- src/alter.c +++ src/alter.c @@ -411,11 +411,11 @@ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - zDb = db->aDb[iDb].zDbSName; + zDb = db->aDb[iDb].zName; db->flags |= SQLITE_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); if( !zName ) goto exit_rename_table; @@ -609,11 +609,11 @@ pNew = pParse->pNewTable; assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); - zDb = db->aDb[iDb].zDbSName; + zDb = db->aDb[iDb].zName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); Index: src/analyze.c ================================================================== --- src/analyze.c +++ src/analyze.c @@ -208,18 +208,18 @@ ** if they do already exist. */ for(i=0; izDbSName))==0 ){ + if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){ if( aTable[i].zCols ){ /* The sqlite_statN table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, - "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols + "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols ); aRoot[i] = pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ @@ -230,11 +230,11 @@ aCreateTbl[i] = 0; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", - pDb->zDbSName, zTab, zWhereType, zWhere + pDb->zName, zTab, zWhereType, zWhere ); }else{ /* The sqlite_stat[134] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); } @@ -992,11 +992,11 @@ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, - db->aDb[iDb].zDbSName ) ){ + db->aDb[iDb].zName ) ){ return; } #endif /* Establish a read-lock on the table at the shared-cache level. @@ -1382,11 +1382,11 @@ } }else{ /* Form 3: Analyze the fully qualified table name */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); if( iDb>=0 ){ - zDb = db->aDb[iDb].zDbSName; + zDb = db->aDb[iDb].zName; z = sqlite3NameFromToken(db, pTableName); if( z ){ if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){ analyzeTable(pParse, pIdx->pTable, pIdx); }else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){ @@ -1842,11 +1842,11 @@ #endif } /* Load new statistics out of the sqlite_stat1 table */ sInfo.db = db; - sInfo.zDatabase = db->aDb[iDb].zDbSName; + sInfo.zDatabase = db->aDb[iDb].zName; if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ zSql = sqlite3MPrintf(db, "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; Index: src/attach.c ================================================================== --- src/attach.c +++ src/attach.c @@ -95,11 +95,11 @@ if( !db->autoCommit ){ zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); goto attach_error; } for(i=0; inDb; i++){ - char *z = db->aDb[i].zDbSName; + char *z = db->aDb[i].zName; assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } @@ -160,12 +160,12 @@ PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif sqlite3BtreeLeave(aNew->pBt); } aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - aNew->zDbSName = sqlite3DbStrDup(db, zName); - if( rc==SQLITE_OK && aNew->zDbSName==0 ){ + aNew->zName = sqlite3DbStrDup(db, zName); + if( rc==SQLITE_OK && aNew->zName==0 ){ rc = SQLITE_NOMEM_BKPT; } #ifdef SQLITE_HAS_CODEC @@ -273,11 +273,11 @@ if( zName==0 ) zName = ""; for(i=0; inDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; - if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break; + if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; } if( i>=db->nDb ){ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); goto detach_error; @@ -431,11 +431,11 @@ sqlite3 *db; db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; - pFix->zDb = db->aDb[iDb].zDbSName; + pFix->zDb = db->aDb[iDb].zName; pFix->pSchema = db->aDb[iDb].pSchema; pFix->zType = zType; pFix->pName = pName; pFix->bVarOnly = (iDb==1); } Index: src/auth.c ================================================================== --- src/auth.c +++ src/auth.c @@ -105,13 +105,13 @@ Parse *pParse, /* The parser context */ const char *zTab, /* Table name */ const char *zCol, /* Column name */ int iDb /* Index of containing database. */ ){ - sqlite3 *db = pParse->db; /* Database handle */ - char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */ - int rc; /* Auth callback return code */ + sqlite3 *db = pParse->db; /* Database handle */ + char *zDb = db->aDb[iDb].zName; /* Name of attached database */ + int rc; /* Auth callback return code */ if( db->init.busy ) return SQLITE_OK; rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser Index: src/backup.c ================================================================== --- src/backup.c +++ src/backup.c @@ -194,10 +194,11 @@ p->pSrcDb = pSrcDb; p->iNext = 1; p->isAttached = 0; if( 0==p->pSrc || 0==p->pDest + || setDestPgsz(p)==SQLITE_NOMEM || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK ){ /* One (or both) of the named databases did not exist or an OOM ** error was hit. Or there is a transaction open on the destination ** database. The error has already been written into the pDestDb @@ -380,10 +381,18 @@ if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){ rc = SQLITE_BUSY; }else{ rc = SQLITE_OK; } + + /* Lock the destination database, if it is not locked already. */ + if( SQLITE_OK==rc && p->bDestLocked==0 + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) + ){ + p->bDestLocked = 1; + sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); + } /* If there is no open read-transaction on the source database, open ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ @@ -390,28 +399,10 @@ if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){ rc = sqlite3BtreeBeginTrans(p->pSrc, 0); bCloseTrans = 1; } - /* If the destination database has not yet been locked (i.e. if this - ** is the first call to backup_step() for the current backup operation), - ** try to set its page size to the same as the source database. This - ** is especially important on ZipVFS systems, as in that case it is - ** not possible to create a database file that uses one page size by - ** writing to it with another. */ - if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){ - rc = SQLITE_NOMEM; - } - - /* Lock the destination database, if it is not locked already. */ - if( SQLITE_OK==rc && p->bDestLocked==0 - && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) - ){ - p->bDestLocked = 1; - sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); - } - /* Do not allow backup if the destination database is in WAL mode ** and the page sizes are different between source and destination */ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); pgszDest = sqlite3BtreeGetPageSize(p->pDest); destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -151,12 +151,12 @@ #if SQLITE_USER_AUTHENTICATION if( pParse->nTableLock>0 && db->init.busy==0 ){ sqlite3UserAuthInit(db); if( db->auth.authLevelrc = SQLITE_AUTH_USER; + sqlite3ErrorMsg(pParse, "user not authenticated"); return; } } #endif @@ -316,15 +316,14 @@ return 0; } #endif for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){ - assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); - if( p ) break; - } + if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; + assert( sqlite3SchemaMutexHeld(db, j, 0) ); + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); + if( p ) break; } return p; } /* @@ -394,11 +393,11 @@ ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); - zDb = pParse->db->aDb[iDb].zDbSName; + zDb = pParse->db->aDb[iDb].zName; }else{ zDb = p->zDatabase; } return sqlite3LocateTable(pParse, flags, p->zName, zDb); } @@ -422,11 +421,11 @@ assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; assert( pSchema ); - if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue; + if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; } return p; @@ -491,12 +490,12 @@ void sqlite3CollapseDatabaseArray(sqlite3 *db){ int i, j; for(i=j=2; inDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ - sqlite3DbFree(db, pDb->zDbSName); - pDb->zDbSName = 0; + sqlite3DbFree(db, pDb->zName); + pDb->zName = 0; continue; } if( jaDb[j] = db->aDb[i]; } @@ -712,11 +711,11 @@ int sqlite3FindDbName(sqlite3 *db, const char *zName){ int i = -1; /* Database number */ if( zName ){ Db *pDb; for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ - if( 0==sqlite3StrICmp(pDb->zDbSName, zName) ) break; + if( 0==sqlite3StrICmp(pDb->zName, zName) ) break; } } return i; } @@ -771,11 +770,11 @@ if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ - assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0); + assert( db->init.iDb==0 || db->init.busy ); iDb = db->init.iDb; *pUnqual = pName1; } return iDb; } @@ -882,11 +881,11 @@ SQLITE_CREATE_TABLE, SQLITE_CREATE_TEMP_TABLE, SQLITE_CREATE_VIEW, SQLITE_CREATE_TEMP_VIEW }; - char *zDb = db->aDb[iDb].zDbSName; + char *zDb = db->aDb[iDb].zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ goto begin_table_error; } if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView], zName, 0, zDb) ){ @@ -901,11 +900,11 @@ ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ if( !IN_DECLARE_VTAB ){ - char *zDb = db->aDb[iDb].zDbSName; + char *zDb = db->aDb[iDb].zName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ @@ -1994,11 +1993,11 @@ */ sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " "WHERE rowid=#%d", - db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zType, p->zName, p->zName, pParse->regRoot, zStmt, @@ -2009,17 +2008,17 @@ #ifndef SQLITE_OMIT_AUTOINCREMENT /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ - if( (p->tabFlags & TF_Autoincrement)!=0 ){ + if( p->tabFlags & TF_Autoincrement ){ Db *pDb = &db->aDb[iDb]; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->pSeqTab==0 ){ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_sequence(name,seq)", - pDb->zDbSName + pDb->zName ); } } #endif @@ -2329,11 +2328,11 @@ ** is in register NNN. See grammar rules associated with the TK_REGISTER ** token for additional information. */ sqlite3NestedParse(pParse, "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d", - pParse->db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), iTable, r1, r1); + pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1); #endif sqlite3ReleaseTempReg(pParse, r1); } /* @@ -2405,11 +2404,11 @@ 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].zDbSName; + const char *zDbName = pParse->db->aDb[iDb].zName; for(i=1; i<=4; i++){ char zTab[24]; sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i); if( sqlite3FindTable(pParse->db, zTab, zDbName) ){ sqlite3NestedParse(pParse, @@ -2458,11 +2457,11 @@ ** 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->zDbSName, pTab->zName + pDb->zName, pTab->zName ); } #endif /* Drop all SQLITE_MASTER table and index entries that refer to the @@ -2472,11 +2471,11 @@ ** 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->zDbSName, SCHEMA_TABLE(iDb), pTab->zName); + 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 @@ -2526,11 +2525,11 @@ } #ifndef SQLITE_OMIT_AUTHORIZATION { int code; const char *zTab = SCHEMA_TABLE(iDb); - const char *zDb = db->aDb[iDb].zDbSName; + const char *zDb = db->aDb[iDb].zName; const char *zArg2 = 0; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ goto exit_drop_table; } if( isView ){ @@ -2767,11 +2766,11 @@ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, - db->aDb[iDb].zDbSName ) ){ + db->aDb[iDb].zName ) ){ return; } #endif /* Require a write-lock on the table to perform this operation */ @@ -3019,11 +3018,11 @@ if( sqlite3FindTable(db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } } - if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ + if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); @@ -3049,11 +3048,11 @@ /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { - const char *zDb = pDb->zDbSName; + const char *zDb = pDb->zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; @@ -3364,11 +3363,11 @@ /* Add an entry in sqlite_master for this index */ sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", - db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName, pTab->zName, iMem, zStmt ); @@ -3498,11 +3497,11 @@ iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; - const char *zDb = db->aDb[iDb].zDbSName; + const char *zDb = db->aDb[iDb].zName; const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX; @@ -3516,11 +3515,11 @@ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", - db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pIndex->zName + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), 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); @@ -4061,11 +4060,11 @@ void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ sqlite3 *db = pParse->db; int i; for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; - if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){ + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){ sqlite3CodeVerifySchema(pParse, i); } } } @@ -4308,11 +4307,11 @@ } iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); if( iDb<0 ) return; z = sqlite3NameFromToken(db, pObjName); if( z==0 ) return; - zDb = db->aDb[iDb].zDbSName; + zDb = db->aDb[iDb].zName; pTab = sqlite3FindTable(db, z, zDb); if( pTab ){ reindexTable(pParse, pTab, 0); sqlite3DbFree(db, z); return; Index: src/dbstat.c ================================================================== --- src/dbstat.c +++ src/dbstat.c @@ -600,11 +600,11 @@ zSql = sqlite3_mprintf( "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" " UNION ALL " "SELECT name, rootpage, type" " FROM \"%w\".%s WHERE rootpage!=0" - " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster); + " ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster); if( zSql==0 ){ return SQLITE_NOMEM_BKPT; }else{ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); sqlite3_free(zSql); @@ -654,11 +654,11 @@ sqlite3_result_int(ctx, pCsr->szPage); break; default: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); int iDb = pCsr->iDb; - sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC); + sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC); break; } } return SQLITE_OK; } Index: src/delete.c ================================================================== --- src/delete.c +++ src/delete.c @@ -100,11 +100,11 @@ pWhere = sqlite3ExprDup(db, pWhere, 0); pFrom = sqlite3SrcListAppend(db, 0, 0, 0); if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); - pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].pUsing==0 ); } pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, SF_IncludeHidden, 0, 0); @@ -287,11 +287,11 @@ if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){ goto delete_from_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); - zDb = db->aDb[iDb].zDbSName; + zDb = db->aDb[iDb].zName; rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb); assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); if( rcauth==SQLITE_DENY ){ goto delete_from_cleanup; } Index: src/fkey.c ================================================================== --- src/fkey.c +++ src/fkey.c @@ -869,11 +869,11 @@ /* If foreign-keys are disabled, this function is a no-op. */ if( (db->flags&SQLITE_ForeignKeys)==0 ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zDb = db->aDb[iDb].zDbSName; + zDb = db->aDb[iDb].zName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ Table *pTo; /* Parent table of foreign key pFKey */ Index: src/insert.c ================================================================== --- src/insert.c +++ src/insert.c @@ -198,13 +198,11 @@ #ifndef SQLITE_OMIT_AUTOINCREMENT /* ** Locate or create an AutoincInfo structure associated with table pTab ** which is in database iDb. Return the register number for the register -** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT -** table. (Also return zero when doing a VACUUM since we do not want to -** update the AUTOINCREMENT counters during a VACUUM.) +** that holds the maximum rowid. ** ** There is at most one AutoincInfo structure per table even if the ** same table is autoincremented multiple times due to inserts within ** triggers. A new AutoincInfo structure is created if this is the ** first use of table pTab. On 2nd and subsequent uses, the original @@ -223,13 +221,11 @@ Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ - if( (pTab->tabFlags & TF_Autoincrement)!=0 - && (pParse->db->flags & SQLITE_Vacuum)==0 - ){ + if( pTab->tabFlags & TF_Autoincrement ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } @@ -549,11 +545,11 @@ goto insert_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); pDb = &db->aDb[iDb]; - zDb = pDb->zDbSName; + zDb = pDb->zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } withoutRowid = !HasRowid(pTab); Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -787,15 +787,10 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; va_start(ap, op); switch( op ){ - case SQLITE_DBCONFIG_MAINDBNAME: { - db->aDb[0].zDbSName = va_arg(ap,char*); - rc = SQLITE_OK; - break; - } case SQLITE_DBCONFIG_LOOKASIDE: { void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */ rc = setupLookaside(db, pBuf, sz, cnt); @@ -2937,13 +2932,13 @@ db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); /* The default safety_level for the main database is FULL; for the temp ** database it is OFF. This matches the pager layer defaults. */ - db->aDb[0].zDbSName = "main"; + db->aDb[0].zName = "main"; db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - db->aDb[1].zDbSName = "temp"; + db->aDb[1].zName = "temp"; db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; db->magic = SQLITE_MAGIC_OPEN; if( db->mallocFailed ){ goto opendb_out; @@ -2953,24 +2948,15 @@ ** database schema yet. This is delayed until the first time the database ** is accessed. */ sqlite3Error(db, SQLITE_OK); sqlite3RegisterPerConnectionBuiltinFunctions(db); - rc = sqlite3_errcode(db); - -#ifdef SQLITE_ENABLE_FTS5 - /* Register any built-in FTS5 module before loading the automatic - ** extensions. This allows automatic extensions to register FTS5 - ** tokenizers and auxiliary functions. */ - if( !db->mallocFailed && rc==SQLITE_OK ){ - rc = sqlite3Fts5Init(db); - } -#endif /* Load automatic extensions - extensions that have been registered ** using the sqlite3_automatic_extension() API. */ + rc = sqlite3_errcode(db); if( rc==SQLITE_OK ){ sqlite3AutoLoadExtensions(db); rc = sqlite3_errcode(db); if( rc!=SQLITE_OK ){ goto opendb_out; @@ -2994,10 +2980,16 @@ #ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */ if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3Fts3Init(db); } #endif + +#ifdef SQLITE_ENABLE_FTS5 + if( !db->mallocFailed && rc==SQLITE_OK ){ + rc = sqlite3Fts5Init(db); + } +#endif #ifdef SQLITE_ENABLE_ICU if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3IcuInit(db); } @@ -3903,11 +3895,11 @@ */ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ int i; for(i=0; inDb; i++){ if( db->aDb[i].pBt - && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zDbSName)==0) + && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0) ){ return db->aDb[i].pBt; } } return 0; Index: src/os_unix.c ================================================================== --- src/os_unix.c +++ src/os_unix.c @@ -5527,31 +5527,10 @@ } #endif /* if !OS_VXWORKS */ return pUnused; } -/* -** Find the mode, uid and gid of file zFile. -*/ -static int getFileMode( - const char *zFile, /* File name */ - mode_t *pMode, /* OUT: Permissions of zFile */ - uid_t *pUid, /* OUT: uid of zFile. */ - gid_t *pGid /* OUT: gid of zFile. */ -){ - struct stat sStat; /* Output of stat() on database file */ - int rc = SQLITE_OK; - if( 0==osStat(zFile, &sStat) ){ - *pMode = sStat.st_mode & 0777; - *pUid = sStat.st_uid; - *pGid = sStat.st_gid; - }else{ - rc = SQLITE_IOERR_FSTAT; - } - return rc; -} - /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is ** written to *pMode. If an IO error occurs, an SQLite error code is @@ -5583,10 +5562,11 @@ *pUid = 0; *pGid = 0; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ + struct stat sStat; /* Output of stat() on database file */ /* zPath is a path to a WAL or journal file. The following block derives ** the path to the associated database file from zPath. This block handles ** the following naming conventions: ** @@ -5613,22 +5593,19 @@ nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; - rc = getFileMode(zDb, pMode, pUid, pGid); + if( 0==osStat(zDb, &sStat) ){ + *pMode = sStat.st_mode & 0777; + *pUid = sStat.st_uid; + *pGid = sStat.st_gid; + }else{ + rc = SQLITE_IOERR_FSTAT; + } }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; - }else if( flags & SQLITE_OPEN_URI ){ - /* If this is a main database file and the file was opened using a URI - ** filename, check for the "modeof" parameter. If present, interpret - ** its value as a filename and try to copy the mode, uid and gid from - ** that file. */ - const char *z = sqlite3_uri_parameter(zPath, "modeof"); - if( z ){ - rc = getFileMode(z, pMode, pUid, pGid); - } } return rc; } /* Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -6654,15 +6654,11 @@ ** This function may return SQLITE_NOMEM if a memory allocation fails, ** or an IO error code if an IO error occurs while rolling back a ** savepoint. If no errors occur, SQLITE_OK is returned. */ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ - int rc = pPager->errCode; - -#ifdef SQLITE_ENABLE_ZIPVFS - if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK; -#endif + int rc = pPager->errCode; /* Return code */ assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK ); if( rc==SQLITE_OK && iSavepointnSavepoint ){ @@ -6699,24 +6695,10 @@ else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){ PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1]; rc = pagerPlaybackSavepoint(pPager, pSavepoint); assert(rc!=SQLITE_DONE); } - -#ifdef SQLITE_ENABLE_ZIPVFS - /* If the cache has been modified but the savepoint cannot be rolled - ** back journal_mode=off, put the pager in the error state. This way, - ** if the VFS used by this pager includes ZipVFS, the entire transaction - ** can be rolled back at the ZipVFS level. */ - else if( - pPager->journalMode==PAGER_JOURNALMODE_OFF - && pPager->eState>=PAGER_WRITER_CACHEMOD - ){ - pPager->errCode = SQLITE_ABORT; - pPager->eState = PAGER_ERROR; - } -#endif } return rc; } Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -1283,12 +1283,12 @@ ///////////////////////////// The VACUUM command ///////////////////////////// // %ifndef SQLITE_OMIT_VACUUM %ifndef SQLITE_OMIT_ATTACH -cmd ::= VACUUM. {sqlite3Vacuum(pParse,0);} -cmd ::= VACUUM nm(X). {sqlite3Vacuum(pParse,&X);} +cmd ::= VACUUM. {sqlite3Vacuum(pParse);} +cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);} %endif SQLITE_OMIT_ATTACH %endif SQLITE_OMIT_VACUUM ///////////////////////////// The PRAGMA command ///////////////////////////// // Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -336,11 +336,11 @@ }else{ zRight = sqlite3NameFromToken(db, pValue); } assert( pId2 ); - zDb = pId2->n>0 ? pDb->zDbSName : 0; + zDb = pId2->n>0 ? pDb->zName : 0; if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ goto pragma_out; } /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS @@ -1189,14 +1189,14 @@ int i; pParse->nMem = 3; setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) ); for(i=0; inDb; i++){ if( db->aDb[i].pBt==0 ) continue; - assert( db->aDb[i].zDbSName!=0 ); + assert( db->aDb[i].zName!=0 ); sqlite3VdbeMultiLoad(v, 1, "iss", i, - db->aDb[i].zDbSName, + db->aDb[i].zName, sqlite3BtreeGetFilename(db->aDb[i].pBt)); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } break; @@ -1481,11 +1481,11 @@ /* Do the b-tree integrity checks */ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); sqlite3VdbeChangeP5(v, (u8)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, - sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), + sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); @@ -1920,19 +1920,19 @@ pParse->nMem = 2; for(i=0; inDb; i++){ Btree *pBt; const char *zState = "unknown"; int j; - if( db->aDb[i].zDbSName==0 ) continue; + if( db->aDb[i].zName==0 ) continue; pBt = db->aDb[i].pBt; if( pBt==0 || sqlite3BtreePager(pBt)==0 ){ zState = "closed"; - }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, + }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0, SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ zState = azLockName[j]; } - sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); + sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } break; } #endif Index: src/prepare.c ================================================================== --- src/prepare.c +++ src/prepare.c @@ -71,11 +71,10 @@ ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data ** structures that describe the table, index, or view. */ int rc; - u8 saved_iDb = db->init.iDb; sqlite3_stmt *pStmt; TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ assert( db->init.busy ); db->init.iDb = iDb; @@ -82,12 +81,11 @@ db->init.newTnum = sqlite3Atoi(argv[1]); db->init.orphanTrigger = 0; TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); - db->init.iDb = saved_iDb; - assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 ); + db->init.iDb = 0; if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ pData->rc = rc; @@ -107,11 +105,11 @@ ** constraint for a CREATE TABLE. The index should have already ** been created when we processed the CREATE TABLE. All we have ** to do here is record the root page number for that index. */ Index *pIndex; - pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName); + pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName); if( pIndex==0 ){ /* This can occur if there exists an index on a TEMP table which ** has the same name as another index on a permanent index. Since ** the permanent table is hidden by the TEMP table, we can also ** safely ignore the index on the permanent table. @@ -286,11 +284,11 @@ assert( db->init.busy ); { char *zSql; zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid", - db->aDb[iDb].zDbSName, zMasterName); + db->aDb[iDb].zName, zMasterName); #ifndef SQLITE_OMIT_AUTHORIZATION { sqlite3_xauth xAuth; xAuth = db->xAuth; db->xAuth = 0; @@ -561,11 +559,11 @@ Btree *pBt = db->aDb[i].pBt; if( pBt ){ assert( sqlite3BtreeHoldsMutex(pBt) ); rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ - const char *zDb = db->aDb[i].zDbSName; + const char *zDb = db->aDb[i].zName; sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); testcase( db->flags & SQLITE_ReadUncommitted ); goto end_prepare; } } Index: src/resolve.c ================================================================== --- src/resolve.c +++ src/resolve.c @@ -219,12 +219,12 @@ ** legacy and because it does not hurt anything to just ignore the ** database name. */ zDb = 0; }else{ for(i=0; inDb; i++){ - assert( db->aDb[i].zDbSName ); - if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){ + assert( db->aDb[i].zName ); + if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ pSchema = db->aDb[i].pSchema; break; } } } Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -1456,11 +1456,11 @@ estWidth = pTab->aCol[iCol].szEst; } zOrigTab = pTab->zName; if( pNC->pParse ){ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); - zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; + zOrigDb = pNC->pParse->db->aDb[iDb].zName; } #else if( iCol<0 ){ zType = "INTEGER"; }else{ @@ -4412,11 +4412,11 @@ pSub = 0; if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; + zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*"; } for(j=0; jnCol; j++){ char *zName = pTab->aCol[j].zName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -522,11 +522,11 @@ } } #if defined(_WIN32) || defined(WIN32) /* For interactive input on Windows systems, translate the ** multi-byte characterset characters into UTF-8. */ - if( stdin_is_interactive ){ + if( stdin_is_interactive && in==stdin ){ char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); if( zTrans ){ int nTrans = strlen30(zTrans)+1; if( nTrans>nLine ){ zLine = realloc(zLine, nTrans); @@ -4903,11 +4903,11 @@ while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){ fflush(p->out); zLine = one_input_line(in, zLine, nSql>0); if( zLine==0 ){ /* End of input */ - if( stdin_is_interactive ) printf("\n"); + if( in==0 && stdin_is_interactive ) printf("\n"); break; } if( seenInterrupt ){ if( in!=0 ) break; seenInterrupt = 0; Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -1967,22 +1967,12 @@ ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may ** be a NULL pointer, in which case the new setting is not reported back. ** ** -**
SQLITE_DBCONFIG_MAINDBNAME
-**
^This option is used to change the name of the "main" database -** schema. ^The sole argument is a pointer to a constant UTF8 string -** which will become the new schema name in place of "main". ^SQLite -** does not make a copy of the new main schema name string, so the application -** must ensure that the argument passed into this DBCONFIG option is unchanged -** until after the database connection closes. -**
-** ** */ -#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1095,11 +1095,11 @@ ** in the sqlite.aDb[] array. aDb[0] is the main database file and ** aDb[1] is the database file used to hold temporary tables. Additional ** databases may be attached. */ struct Db { - char *zDbSName; /* Name of this database. (schema name, not filename) */ + char *zName; /* Name of this database */ Btree *pBt; /* The B*Tree structure for this database file */ u8 safety_level; /* How aggressive at syncing data to disk */ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; @@ -3699,12 +3699,12 @@ Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); -void sqlite3Vacuum(Parse*,Token*); -int sqlite3RunVacuum(char**, sqlite3*, int); +void sqlite3Vacuum(Parse*); +int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*, int); int sqlite3ExprListCompare(ExprList*, ExprList*, int); int sqlite3ExprImpliesExpr(Expr*, Expr*, int); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -7193,33 +7193,10 @@ sqlite3_db_config(db, aSetting[i].eVal, v, &v); Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); return TCL_OK; } -/* -** Change the name of the main database schema from "main" to "icecube". -*/ -static int SQLITE_TCLAPI test_dbconfig_maindbname_icecube( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - int rc; - sqlite3 *db; - extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "DB"); - return TCL_ERROR; - }else{ - if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; - rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "icecube"); - Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); - return TCL_OK; - } -} - /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; @@ -7349,11 +7326,10 @@ { "sqlite3_load_extension", test_load_extension, 0}, { "sqlite3_enable_load_extension", test_enable_load, 0}, { "sqlite3_extended_result_codes", test_extended_result_codes, 0}, { "sqlite3_limit", test_limit, 0}, - { "dbconfig_maindbname_icecube", test_dbconfig_maindbname_icecube }, { "save_prng_state", save_prng_state, 0 }, { "restore_prng_state", restore_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 }, { "database_never_corrupt", database_never_corrupt, 0}, Index: src/tokenize.c ================================================================== --- src/tokenize.c +++ src/tokenize.c @@ -500,30 +500,18 @@ assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->nzVar==0 ); assert( pParse->azVar==0 ); - while( 1 ){ + while( zSql[i]!=0 ){ assert( i>=0 ); - if( zSql[i]!=0 ){ - pParse->sLastToken.z = &zSql[i]; - pParse->sLastToken.n = sqlite3GetToken((u8*)&zSql[i],&tokenType); - i += pParse->sLastToken.n; - if( i>mxSqlLen ){ - pParse->rc = SQLITE_TOOBIG; - break; - } - }else{ - /* Upon reaching the end of input, call the parser two more times - ** with tokens TK_SEMI and 0, in that order. */ - if( lastTokenParsed==TK_SEMI ){ - tokenType = 0; - }else if( lastTokenParsed==0 ){ - break; - }else{ - tokenType = TK_SEMI; - } + pParse->sLastToken.z = &zSql[i]; + pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType); + i += pParse->sLastToken.n; + if( i>mxSqlLen ){ + pParse->rc = SQLITE_TOOBIG; + break; } if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); if( db->u1.isInterrupted ){ pParse->rc = SQLITE_INTERRUPT; @@ -540,10 +528,19 @@ if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; } } assert( nErr==0 ); pParse->zTail = &zSql[i]; + if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ + assert( zSql[i]==0 ); + if( lastTokenParsed!=TK_SEMI ){ + sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse); + } + if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ + sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); + } + } #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, sqlite3ParserStackPeak(pEngine) ); Index: src/treeview.c ================================================================== --- src/treeview.c +++ src/treeview.c @@ -118,11 +118,11 @@ } } /* -** Generate a human-readable description of a Select object. +** Generate a human-readable description of a the Select object. */ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; int cnt = 0; pView = sqlite3TreeViewPush(pView, moreToFollow); Index: src/trigger.c ================================================================== --- src/trigger.c +++ src/trigger.c @@ -212,12 +212,12 @@ iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_CREATE_TRIGGER; - const char *zDb = db->aDb[iTabDb].zDbSName; - const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb; + const char *zDb = db->aDb[iTabDb].zName; + const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb; if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ goto trigger_cleanup; } if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ @@ -307,11 +307,11 @@ if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", - db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), zName, + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); @@ -496,11 +496,11 @@ zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue; + if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; } if( !pTrigger ){ @@ -542,11 +542,11 @@ assert( pTable ); assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; - const char *zDb = db->aDb[iDb].zDbSName; + const char *zDb = db->aDb[iDb].zName; const char *zTab = SCHEMA_TABLE(iDb); if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ return; @@ -558,11 +558,11 @@ */ assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", - db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pTrigger->zName + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); } } @@ -661,14 +661,12 @@ if( pSrc ){ assert( pSrc->nSrc>0 ); pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); if( iDb==0 || iDb>=2 ){ - const char *zDb; assert( iDbnDb ); - zDb = db->aDb[iDb].zDbSName; - pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb); + pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); } } return pSrc; } Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -247,11 +247,11 @@ #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, j<0 ? "ROWID" : pTab->aCol[j].zName, - db->aDb[iDb].zDbSName); + db->aDb[iDb].zName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } Index: src/vacuum.c ================================================================== --- src/vacuum.c +++ src/vacuum.c @@ -16,56 +16,61 @@ */ #include "sqliteInt.h" #include "vdbeInt.h" #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) +/* +** Finalize a prepared statement. If there was an error, store the +** text of the error message in *pzErrMsg. Return the result code. +*/ +static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){ + int rc; + rc = sqlite3VdbeFinalize((Vdbe*)pStmt); + if( rc ){ + sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); + } + return rc; +} /* -** Execute zSql on database db. -** -** If zSql returns rows, then each row will have exactly one -** column. (This will only happen if zSql begins with "SELECT".) -** Take each row of result and call execSql() again recursively. -** -** The execSqlF() routine does the same thing, except it accepts -** a format string as its third argument +** Execute zSql on database db. Return an error code. */ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ sqlite3_stmt *pStmt; - int rc; - - /* printf("SQL: [%s]\n", zSql); fflush(stdout); */ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ) return rc; - while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ - const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); - assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); - if( zSubSql ){ - assert( zSubSql[0]!='S' ); - rc = execSql(db, pzErrMsg, zSubSql); - if( rc!=SQLITE_OK ) break; - } - } - assert( rc!=SQLITE_ROW ); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - if( rc ){ - sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); - } - (void)sqlite3_finalize(pStmt); - return rc; -} -static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){ - char *z; - va_list ap; - int rc; - va_start(ap, zSql); - z = sqlite3VMPrintf(db, zSql, ap); - va_end(ap); - if( z==0 ) return SQLITE_NOMEM; - rc = execSql(db, pzErrMsg, z); - sqlite3DbFree(db, z); - return rc; + VVA_ONLY( int rc; ) + if( !zSql ){ + return SQLITE_NOMEM_BKPT; + } + if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ + sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); + return sqlite3_errcode(db); + } + VVA_ONLY( rc = ) sqlite3_step(pStmt); + assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) ); + return vacuumFinalize(db, pStmt, pzErrMsg); +} + +/* +** Execute zSql on database db. The statement returns exactly +** one column. Execute this as SQL on the same database. +*/ +static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ + sqlite3_stmt *pStmt; + int rc; + + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0)); + if( rc!=SQLITE_OK ){ + vacuumFinalize(db, pStmt, pzErrMsg); + return rc; + } + } + + return vacuumFinalize(db, pStmt, pzErrMsg); } /* ** The VACUUM command is used to clean up the database, ** collapse free space, etc. It is modelled after the VACUUM command @@ -94,36 +99,35 @@ ** not work if other processes are attached to the original database. ** And a power loss in between deleting the original and renaming the ** transient would cause the database file to appear to be deleted ** following reboot. */ -void sqlite3Vacuum(Parse *pParse, Token *pNm){ +void sqlite3Vacuum(Parse *pParse){ Vdbe *v = sqlite3GetVdbe(pParse); - int iDb = pNm ? sqlite3TwoPartName(pParse, pNm, pNm, &pNm) : 0; - if( v && (iDb>=2 || iDb==0) ){ - sqlite3VdbeAddOp1(v, OP_Vacuum, iDb); - sqlite3VdbeUsesBtree(v, iDb); + if( v ){ + sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0); + sqlite3VdbeUsesBtree(v, 0); } return; } /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ -int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ +int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ + char *zSql = 0; /* SQL statements */ int saved_flags; /* Saved value of the db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ - const char *zDbMain; /* Schema name of database to vacuum */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; } @@ -137,17 +141,15 @@ ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; - db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks - | SQLITE_PreferBuiltin | SQLITE_Vacuum); - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin; + db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); db->mTrace = 0; - zDbMain = db->aDb[iDb].zDbSName; - pMain = db->aDb[iDb].pBt; + pMain = db->aDb[0].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); /* Attach the temporary database as 'vacuum_db'. The synchronous pragma ** can be set to 'off' for this file, as it is not recovered if a crash ** occurs anyway. The integrity of the database is maintained by a @@ -161,16 +163,22 @@ ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ nDb = db->nDb; - rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db"); + if( sqlite3TempInMemory(db) ){ + zSql = "ATTACH ':memory:' AS vacuum_db;"; + }else{ + zSql = "ATTACH '' AS vacuum_db;"; + } + rc = execSql(db, pzErrMsg, zSql); + if( db->nDb>nDb ){ + pDb = &db->aDb[db->nDb-1]; + assert( strcmp(pDb->zName,"vacuum_db")==0 ); + } if( rc!=SQLITE_OK ) goto end_of_vacuum; - assert( (db->nDb-1)==nDb ); - pDb = &db->aDb[nDb]; - assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); - pTemp = pDb->pBt; + pTemp = db->aDb[db->nDb-1].pBt; /* The call to execSql() to attach the temp database has left the file ** locked (as there was more than one active statement when the transaction ** to read the schema was concluded. Unlock it here so that this doesn't ** cause problems for the call to BtreeSetPageSize() below. */ @@ -187,19 +195,20 @@ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); if( nKey ) db->nextPagesize = 0; } #endif - sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); + sqlite3BtreeSetCacheSize(pTemp, db->aDb[0].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); - sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF); + rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); + if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Begin a transaction and take an exclusive lock on the main database ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, ** to ensure that we do not try to change the page-size on a WAL database. */ - rc = execSql(db, pzErrMsg, "BEGIN"); + rc = execSql(db, pzErrMsg, "BEGIN;"); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = sqlite3BtreeBeginTrans(pMain, 2); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Do not attempt to change the page size for a WAL database */ @@ -222,52 +231,68 @@ #endif /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ - db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ - rc = execSqlF(db, pzErrMsg, - "SELECT sql FROM \"%w\".sqlite_master" - " WHERE type='table'AND name<>'sqlite_sequence'" - " AND coalesce(rootpage,1)>0", - zDbMain - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execSqlF(db, pzErrMsg, - "SELECT sql FROM \"%w\".sqlite_master" - " WHERE type='index' AND length(sql)>10", - zDbMain - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - db->init.iDb = 0; + rc = execExecSql(db, pzErrMsg, + "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) " + " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" + " AND coalesce(rootpage,1)>0" + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = execExecSql(db, pzErrMsg, + "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" + " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = execExecSql(db, pzErrMsg, + "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " + " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); + if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Loop through the tables in the main database. For each, do ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ - rc = execSqlF(db, pzErrMsg, - "SELECT'INSERT INTO vacuum_db.'||quote(name)" - "||' SELECT*FROM\"%w\".'||quote(name)" - "FROM vacuum_db.sqlite_master " - "WHERE type='table'AND coalesce(rootpage,1)>0", - zDbMain + assert( (db->flags & SQLITE_Vacuum)==0 ); + db->flags |= SQLITE_Vacuum; + rc = execExecSql(db, pzErrMsg, + "SELECT 'INSERT INTO vacuum_db.' || quote(name) " + "|| ' SELECT * FROM main.' || quote(name) || ';'" + "FROM main.sqlite_master " + "WHERE type = 'table' AND name!='sqlite_sequence' " + " AND coalesce(rootpage,1)>0" ); assert( (db->flags & SQLITE_Vacuum)!=0 ); db->flags &= ~SQLITE_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; + + /* Copy over the sequence table + */ + rc = execExecSql(db, pzErrMsg, + "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " + "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' " + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = execExecSql(db, pzErrMsg, + "SELECT 'INSERT INTO vacuum_db.' || quote(name) " + "|| ' SELECT * FROM main.' || quote(name) || ';' " + "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';" + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries ** from the SQLITE_MASTER table. */ - rc = execSqlF(db, pzErrMsg, - "INSERT INTO vacuum_db.sqlite_master" - " SELECT*FROM \"%w\".sqlite_master" - " WHERE type IN('view','trigger')" - " OR(type='table'AND rootpage=0)", - zDbMain + rc = execSql(db, pzErrMsg, + "INSERT INTO vacuum_db.sqlite_master " + " SELECT type, name, tbl_name, rootpage, sql" + " FROM main.sqlite_master" + " WHERE type='view' OR type='trigger'" + " OR (type='table' AND rootpage=0)" ); if( rc ) goto end_of_vacuum; /* At this point, there is a write transaction open on both the ** vacuum database and the main database. Assuming no error occurs, @@ -317,11 +342,10 @@ assert( rc==SQLITE_OK ); rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1); end_of_vacuum: /* Restore the original value of db->flags */ - db->init.iDb = 0; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; db->mTrace = saved_mTrace; sqlite3BtreeSetPageSize(pMain, -1, -1, 1); Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -4344,11 +4344,11 @@ } if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->isTable ); assert( pC->iDb>=0 ); - zDb = db->aDb[pC->iDb].zDbSName; + zDb = db->aDb[pC->iDb].zName; pTab = pOp->p4.pTab; assert( HasRowid(pTab) ); op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); }else{ pTab = 0; /* Not needed. Silence a comiler warning. */ @@ -4461,11 +4461,11 @@ ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set ** VdbeCursor.movetoTarget to the current rowid. */ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); assert( pOp->p4.pTab!=0 ); - zDb = db->aDb[pC->iDb].zDbSName; + zDb = db->aDb[pC->iDb].zName; pTab = pOp->p4.pTab; if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ @@ -5431,11 +5431,11 @@ initData.db = db; initData.iDb = pOp->p1; initData.pzErrMsg = &p->zErrMsg; zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", - db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); + db->aDb[iDb].zName, zMaster, pOp->p4.z); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); db->init.busy = 1; @@ -6260,18 +6260,19 @@ break; }; #endif /* SQLITE_OMIT_PRAGMA */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) -/* Opcode: Vacuum P1 * * * * +/* Opcode: Vacuum * * * * * ** -** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more -** for an attached database. The "temp" database may not be vacuumed. +** Vacuum the entire database. This opcode will cause other virtual +** machines to be created and run. It may not be called from within +** a transaction. */ case OP_Vacuum: { assert( p->readOnly==0 ); - rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1); + rc = sqlite3RunVacuum(&p->zErrMsg, db); if( rc ) goto abort_due_to_error; break; } #endif @@ -6814,11 +6815,11 @@ zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ int i; for(i=0; inDb; i++){ if( DbMaskTest(p->btreeMask, i)==0 ) continue; - sqlite3_file_control(db, db->aDb[i].zDbSName, SQLITE_FCNTL_TRACE, zTrace); + sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace); } } #endif /* SQLITE_USE_FCNTL_TRACE */ #ifdef SQLITE_DEBUG if( (db->flags & SQLITE_SqlTrace)!=0 Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -497,11 +497,11 @@ int nEntry; sqlite3BtreeEnter(pBt); nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ - rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry); + rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry); } } } #endif return rc; Index: src/vdbeblob.c ================================================================== --- src/vdbeblob.c +++ src/vdbeblob.c @@ -174,11 +174,11 @@ rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); goto blob_open_out; } pBlob->pTab = pTab; - pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zName; /* Now search pTab for the exact column. */ for(iCol=0; iColnCol; iCol++) { if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){ break; Index: src/vtab.c ================================================================== --- src/vtab.c +++ src/vtab.c @@ -342,11 +342,11 @@ ** sqlite_master table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ if( pTable->azModuleArg ){ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, - pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); + pTable->azModuleArg[0], pParse->db->aDb[iDb].zName); } #endif } /* @@ -406,11 +406,11 @@ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", - db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTab->zName, pTab->zName, zStmt, pParse->regRowid ); @@ -516,11 +516,11 @@ } pVTable->db = db; pVTable->pMod = pMod; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - pTab->azModuleArg[1] = db->aDb[iDb].zDbSName; + pTab->azModuleArg[1] = db->aDb[iDb].zName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); assert( xConstruct ); sCtx.pTab = pTab; @@ -670,21 +670,21 @@ /* ** This function is invoked by the vdbe to call the xCreate method ** of the virtual table named zTab in database iDb. ** -** If an error occurs, *pzErr is set to point to an English language +** If an error occurs, *pzErr is set to point an an English language ** description of the error and an SQLITE_XXX error code is returned. ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr. */ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; Table *pTab; Module *pMod; const char *zMod; - pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable ); /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); @@ -804,11 +804,11 @@ */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; - pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->pVTable; p; p=p->pNext){ assert( p->pVtab ); Index: src/walker.c ================================================================== --- src/walker.c +++ src/walker.c @@ -39,19 +39,21 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); rc = pWalker->xExprCallback(pWalker, pExpr); - if( rc || ExprHasProperty(pExpr,EP_TokenOnly) ) return rc & WRC_Abort; - if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; - if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; - }else{ - if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; - } - return WRC_Continue; + if( rc==WRC_Continue + && !ExprHasProperty(pExpr,EP_TokenOnly) ){ + if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; + if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; + }else{ + if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + } + } + return rc & WRC_Abort; } int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; } Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -3399,10 +3399,18 @@ if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, eqOpMask, 0); if( pTerm==0 ) continue; + if( pTerm->eOperator==WO_IN ){ + /* IN terms are only valid for sorting in the ORDER BY LIMIT + ** optimization, and then only if they are actually used + ** by the query plan */ + assert( wctrlFlags & WHERE_ORDERBY_LIMIT ); + for(j=0; jnLTerm && pTerm!=pLoop->aLTerm[j]; j++){} + if( j>=pLoop->nLTerm ) continue; + } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ const char *z1, *z2; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; z1 = pColl->zName; Index: src/wherecode.c ================================================================== --- src/wherecode.c +++ src/wherecode.c @@ -534,13 +534,19 @@ regBase = r1; }else{ sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); } } - testcase( pTerm->eOperator & WO_ISNULL ); - testcase( pTerm->eOperator & WO_IN ); - if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ + if( (pTerm->eOperator & WO_IN)!=0 ){ + if( pTerm->pExpr->flags & EP_xIsSelect ){ + /* No affinity ever needs to be (or should be) applied to a value + ** from the RHS of an "? IN (SELECT ...)" expression. The + ** sqlite3FindInIndex() routine has already ensured that the + ** affinity of the comparison has been applied to the value. */ + if( zAff ) zAff[j] = SQLITE_AFF_BLOB; + } + }else if( (pTerm->eOperator & WO_ISNULL)==0 ){ Expr *pRight = pTerm->pExpr->pRight; if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); } Index: src/whereexpr.c ================================================================== --- src/whereexpr.c +++ src/whereexpr.c @@ -288,11 +288,11 @@ */ static int isMatchOfColumn( Expr *pExpr, /* Test this expression */ unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */ ){ - static const struct Op2 { + struct Op2 { const char *zOp; unsigned char eOp2; } aOp[] = { { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, @@ -1273,18 +1273,17 @@ ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. */ Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ - Bitmask mask; + Bitmask mask = 0; if( p==0 ) return 0; if( p->op==TK_COLUMN ){ mask = sqlite3WhereGetMask(pMaskSet, p->iTable); return mask; } - assert( !ExprHasProperty(p, EP_TokenOnly) ); - mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0; + mask = sqlite3WhereExprUsage(pMaskSet, p->pRight); if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); if( ExprHasProperty(p, EP_xIsSelect) ){ mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); Index: test/backup_malloc.test ================================================================== --- test/backup_malloc.test +++ test/backup_malloc.test @@ -82,37 +82,6 @@ } -cleanup { catch { B finish } db2 close } -reset_db -do_execsql_test 3.0 { - PRAGMA page_size = 16384; - BEGIN; - CREATE TABLE t1(a, b); - INSERT INTO t1 VALUES(1, 2); - COMMIT; -} - -do_faultsim_test 3 -faults oom* -prep { - catch { db close } - - forcedelete test2.db - sqlite3 db2 test2.db - sqlite3 db test.db - sqlite3_backup B db2 main db main -} -body { - - set rc [B step 50] - if {$rc == "SQLITE_NOMEM" || $rc == "SQLITE_IOERR_NOMEM"} { - error "out of memory" - } - -} -test { - faultsim_test_result {0 {}} - faultsim_integrity_check - - # Finalize the backup. - catch { B finish } -} - finish_test Index: test/e_vacuum.test ================================================================== --- test/e_vacuum.test +++ test/e_vacuum.test @@ -200,12 +200,16 @@ CREATE TABLE aux.t3 AS SELECT * FROM t1; DELETE FROM t3; } {} set original_size [file size test.db2] -# Vacuuming the main database does not affect aux +# Try everything we can think of to get the aux database vacuumed: do_execsql_test e_vacuum-2.1.3 { VACUUM } {} +do_execsql_test e_vacuum-2.1.4 { VACUUM aux } {} +do_execsql_test e_vacuum-2.1.5 { VACUUM 'test.db2' } {} + +# Despite our efforts, space in the aux database has not been reclaimed: do_test e_vacuum-2.1.6 { expr {[file size test.db2]==$::original_size} } 1 # EVIDENCE-OF: R-17495-17419 The VACUUM command may change the ROWIDs of # entries in any tables that do not have an explicit INTEGER PRIMARY # KEY. Index: test/limit2.test ================================================================== --- test/limit2.test +++ test/limit2.test @@ -94,11 +94,22 @@ } {2 2 2 12345 |} do_execsql_test limit2-210 { SELECT *, '|' FROM t200 LEFT JOIN t201 ON x=b ORDER BY y LIMIT 3; } {1 1 {} {} | 3 3 {} {} | 4 4 {} {} |} - +# Bug in the ORDER BY LIMIT optimization reported on 2016-09-06. +# Ticket https://www.sqlite.org/src/info/559733b09e96 +# +do_execsql_test limit2-300 { + CREATE TABLE t300(a,b,c); + CREATE INDEX t300x ON t300(a,b,c); + INSERT INTO t300 VALUES(0,1,99),(0,1,0),(0,0,0); + SELECT *,'.' FROM t300 WHERE a=0 AND (c=0 OR c=99) ORDER BY c DESC; +} {0 1 99 . 0 0 0 . 0 1 0 .} +do_execsql_test limit2-310 { + SELECT *,'.' FROM t300 WHERE a=0 AND (c=0 OR c=99) ORDER BY c DESC LIMIT 1; +} {0 1 99 .} finish_test Index: test/misc8.test ================================================================== --- test/misc8.test +++ test/misc8.test @@ -105,33 +105,7 @@ ) AS x3, (SELECT 6 AS j UNION ALL SELECT 7) AS x4 WHERE ibase; - return SQLITE_OK; -} - -/* -** Destructor for a series_cursor. -*/ -static int seriesClose(sqlite3_vtab_cursor *cur){ - sqlite3_free(cur); - return SQLITE_OK; -} - - -/* -** Advance a series_cursor to its next row of output. -*/ -static int seriesNext(sqlite3_vtab_cursor *cur){ - series_cursor *pCur = (series_cursor*)cur; - if( pCur->isDesc ){ - pCur->iValue -= pCur->iStep; - }else{ - pCur->iValue += pCur->iStep; - } - pCur->iRowid++; - return SQLITE_OK; -} - -/* -** Return values of columns for the row at which the series_cursor -** is currently pointing. -*/ -static int seriesColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - series_cursor *pCur = (series_cursor*)cur; - sqlite3_int64 x = 0; - switch( i ){ - case SERIES_COLUMN_START: x = pCur->mnValue; break; - case SERIES_COLUMN_STOP: x = pCur->mxValue; break; - case SERIES_COLUMN_STEP: x = pCur->iStep; break; - default: x = pCur->iValue; break; - } - sqlite3_result_int64(ctx, x); - return SQLITE_OK; -} - -/* -** Return the rowid for the current row. In this implementation, the -** rowid is the same as the output value. -*/ -static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - series_cursor *pCur = (series_cursor*)cur; - *pRowid = pCur->iRowid; - return SQLITE_OK; -} - -/* -** Return TRUE if the cursor has been moved off of the last -** row of output. -*/ -static int seriesEof(sqlite3_vtab_cursor *cur){ - series_cursor *pCur = (series_cursor*)cur; - if( pCur->isDesc ){ - return pCur->iValue < pCur->mnValue; - }else{ - return pCur->iValue > pCur->mxValue; - } -} - -/* True to cause run-time checking of the start=, stop=, and/or step= -** parameters. The only reason to do this is for testing the -** constraint checking logic for virtual tables in the SQLite core. -*/ -#ifndef SQLITE_SERIES_CONSTRAINT_VERIFY -# define SQLITE_SERIES_CONSTRAINT_VERIFY 0 -#endif - -/* -** This method is called to "rewind" the series_cursor object back -** to the first row of output. This method is always called at least -** once prior to any call to seriesColumn() or seriesRowid() or -** seriesEof(). -** -** The query plan selected by seriesBestIndex is passed in the idxNum -** parameter. (idxStr is not used in this implementation.) idxNum -** is a bitmask showing which constraints are available: -** -** 1: start=VALUE -** 2: stop=VALUE -** 4: step=VALUE -** -** Also, if bit 8 is set, that means that the series should be output -** in descending order rather than in ascending order. -** -** This routine should initialize the cursor and position it so that it -** is pointing at the first row, or pointing off the end of the table -** (so that seriesEof() will return true) if the table is empty. -*/ -static int seriesFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - series_cursor *pCur = (series_cursor *)pVtabCursor; - int i = 0; - if( idxNum & 1 ){ - pCur->mnValue = sqlite3_value_int64(argv[i++]); - }else{ - pCur->mnValue = 0; - } - if( idxNum & 2 ){ - pCur->mxValue = sqlite3_value_int64(argv[i++]); - }else{ - pCur->mxValue = 0xffffffff; - } - if( idxNum & 4 ){ - pCur->iStep = sqlite3_value_int64(argv[i++]); - if( pCur->iStep<1 ) pCur->iStep = 1; - }else{ - pCur->iStep = 1; - } - if( idxNum & 8 ){ - pCur->isDesc = 1; - pCur->iValue = pCur->mxValue; - if( pCur->iStep>0 ){ - pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep; - } - }else{ - pCur->isDesc = 0; - pCur->iValue = pCur->mnValue; - } - pCur->iRowid = 1; - return SQLITE_OK; -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the generate_series virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -** -** In this implementation idxNum is used to represent the -** query plan. idxStr is unused. -** -** The query plan is represented by bits in idxNum: -** -** (1) start = $value -- constraint exists -** (2) stop = $value -- constraint exists -** (4) step = $value -- constraint exists -** (8) output in descending order -*/ -static int seriesBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - int i; /* Loop over constraints */ - int idxNum = 0; /* The query plan bitmask */ - int startIdx = -1; /* Index of the start= constraint, or -1 if none */ - int stopIdx = -1; /* Index of the stop= constraint, or -1 if none */ - int stepIdx = -1; /* Index of the step= constraint, or -1 if none */ - int nArg = 0; /* Number of arguments that seriesFilter() expects */ - - const struct sqlite3_index_constraint *pConstraint; - pConstraint = pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->usable==0 ) continue; - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case SERIES_COLUMN_START: - startIdx = i; - idxNum |= 1; - break; - case SERIES_COLUMN_STOP: - stopIdx = i; - idxNum |= 2; - break; - case SERIES_COLUMN_STEP: - stepIdx = i; - idxNum |= 4; - break; - } - } - if( startIdx>=0 ){ - pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[startIdx].omit= !SQLITE_SERIES_CONSTRAINT_VERIFY; - } - if( stopIdx>=0 ){ - pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[stopIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY; - } - if( stepIdx>=0 ){ - pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[stepIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY; - } - if( (idxNum & 3)==3 ){ - /* Both start= and stop= boundaries are available. This is the - ** the preferred case */ - pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0)); - pIdxInfo->estimatedRows = 1000; - if( pIdxInfo->nOrderBy==1 ){ - if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8; - pIdxInfo->orderByConsumed = 1; - } - }else{ - /* If either boundary is missing, we have to generate a huge span - ** of numbers. Make this case very expensive so that the query - ** planner will work hard to avoid it. */ - pIdxInfo->estimatedCost = (double)2147483647; - pIdxInfo->estimatedRows = 2147483647; - } - pIdxInfo->idxNum = idxNum; - return SQLITE_OK; -} - -/* -** This following structure defines all the methods for the -** generate_series virtual table. -*/ -static sqlite3_module seriesModule = { - 0, /* iVersion */ - 0, /* xCreate */ - seriesConnect, /* xConnect */ - seriesBestIndex, /* xBestIndex */ - seriesDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - seriesOpen, /* xOpen - open a cursor */ - seriesClose, /* xClose - close a cursor */ - seriesFilter, /* xFilter - configure scan constraints */ - seriesNext, /* xNext - advance a cursor */ - seriesEof, /* xEof - check for end of scan */ - seriesColumn, /* xColumn - read data */ - seriesRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ -}; -/* END the generate_series(START,END,STEP) implementation -*********************************************************************************/ - /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] ?FILE...?\n", g.zArgv0); @@ -1047,11 +727,10 @@ #ifndef SQLITE_OMIT_TRACE sqlite3_trace(db, verboseFlag ? traceCallback : traceNoop, 0); #endif sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); - sqlite3_create_module(db, "generate_series", &seriesModule, 0); sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000); if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding); if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize); if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL"); iStart = timeOfDay(); Index: tool/lemon.c ================================================================== --- tool/lemon.c +++ tool/lemon.c @@ -261,12 +261,11 @@ char *firstset; /* First-set for all rules of this symbol */ Boolean lambda; /* True if NT and can generate an empty string */ int useCnt; /* Number of times used */ char *destructor; /* Code which executes whenever this symbol is ** popped from the stack during error processing */ - int destLineno; /* Line number for start of destructor. Set to - ** -1 for duplicate destructors. */ + int destLineno; /* Line number for start of destructor */ char *datatype; /* The data type of information held by this ** object. Only used if type==NONTERMINAL */ int dtnum; /* The data type number. In the parser, the value ** stack is a union. The .yy%d element of this ** union is the correct data type for this object */ @@ -4230,25 +4229,24 @@ } } fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ + fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; - fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", lemp->nactiontab); lineno++; - fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; - fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; - fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; + fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; + fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; + fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; fprintf(out, "static const %s yy_shift_ofst[] = {\n", - minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz)); - lineno++; + minimum_size_type(mnTknOfst-1, mxTknOfst, &sz)); lineno++; lemp->tablesize += n*sz; for(i=j=0; isorted[i]; ofst = stp->iTknOfst; - if( ofst==NO_OFFSET ) ofst = lemp->nactiontab; + if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", ofst); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; @@ -4384,11 +4382,10 @@ fprintf(out," break;\n"); lineno++; } for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; - if( sp->destLineno<0 ) continue; /* Already emitted */ fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; /* Combine duplicate destructors into a single case */ for(j=i+1; jnsymbol; j++){ struct symbol *sp2 = lemp->symbols[j]; @@ -4395,11 +4392,11 @@ if( sp2 && sp2->type!=TERMINAL && sp2->destructor && sp2->dtnum==sp->dtnum && strcmp(sp->destructor,sp2->destructor)==0 ){ fprintf(out," case %d: /* %s */\n", sp2->index, sp2->name); lineno++; - sp2->destLineno = -1; /* Avoid emitting this destructor again */ + sp2->destructor = 0; } } emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); fprintf(out," break;\n"); lineno++; Index: tool/lempar.c ================================================================== --- tool/lempar.c +++ tool/lempar.c @@ -114,33 +114,29 @@ ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE ** and YY_MAX_REDUCE -** + ** N == YY_ERROR_ACTION A syntax error has occurred. ** ** N == YY_ACCEPT_ACTION The parser accepts its input. ** ** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. -** Given state S and lookahead X, the action is computed as either: -** -** (A) N = yy_action[ yy_shift_ofst[S] + X ] -** (B) N = yy_default[S] -** -** The (A) formula is preferred. The B formula is used instead if: -** (1) The yy_shift_ofst[S]+X value is out of range, or -** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or -** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. -** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that -** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. -** Hence only tests (1) and (2) need to be evaluated.) -** -** The formulas above are for computing the action when the lookahead is +** Given state S and lookahead X, the action is computed as +** +** yy_action[ yy_shift_ofst[S] + X ] +** +** If the index value yy_shift_ofst[S]+X is out of range or if the value +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table +** and that yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of ** YY_SHIFT_USE_DFLT. ** @@ -452,51 +448,54 @@ if( stateno>=YY_MIN_REDUCE ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); do{ i = yy_shift_ofst[stateno]; + if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + if( iLookAhead>0 ){ #ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } #endif - assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ - iLookAhead = iFallback; - continue; - } + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } #endif #ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( + { + int j = i - iLookAhead + YYWILDCARD; + if( #if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && + j>=0 && #endif #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j0 - ){ + yy_lookahead[j]==YYWILDCARD + ){ #ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], - yyTokenName[YYWILDCARD]); - } + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + } #endif /* NDEBUG */ - return yy_action[j]; + return yy_action[j]; + } } - } #endif /* YYWILDCARD */ + } return yy_default[stateno]; }else{ return yy_action[i]; } }while(1); Index: tool/mksqlite3c-noext.tcl ================================================================== --- tool/mksqlite3c-noext.tcl +++ tool/mksqlite3c-noext.tcl @@ -1,19 +1,19 @@ #!/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 +# 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 +# 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: # @@ -24,19 +24,24 @@ # Begin by reading the "sqlite3.h" header file. Extract the version number # from in this file. The version 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 addstatic 1 +set linemacros 0 +set useapicall 0 +for {set i 0} {$i<[llength $argv]} {incr i} { + set x [lindex $argv $i] + if {[regexp {^-+nostatic$} $x]} { + set addstatic 0 + } elseif {[regexp {^-+linemacros} $x]} { + set linemacros 1 + } elseif {[regexp {^-+useapicall} $x]} { + set useapicall 1 + } else { + error "unknown command-line option: $x" + } } set in [open tsrc/sqlite3.h] set cnt 0 set VERSION ????? while {![eof $in]} { @@ -55,20 +60,20 @@ 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 +** 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 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 @@ -81,11 +86,11 @@ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif} } -# These are the header files used by SQLite. The first time any of these +# 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 @@ -102,12 +107,12 @@ os.h pager.h parse.h pcache.h pragma.h - sqlite3ext.h sqlite3.h + sqlite3ext.h sqliteicu.h sqliteInt.h sqliteLimit.h vdbe.h vdbeInt.h @@ -153,11 +158,12 @@ # Read the source file named $filename and write it into the # sqlite3.c output file. If any #include statements are seen, # process them appropriately. # proc copy_file {filename} { - global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros + global seen_hdr available_hdr varonly_hdr cdecllist out + global addstatic linemacros useapicall 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] @@ -201,30 +207,33 @@ } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {!$linemacros && [regexp {^#line} $line]} { # Skip #line directives. - } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { + } elseif {$addstatic + && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} { # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before # functions if this header file does not need it. if {![info exists varonly_hdr($tail)] && [regexp $declpattern $line all rettype funcname rest]} { regsub {^SQLITE_API } $line {} line # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. # so that linkage can be modified at compile-time. - if {[regexp {^sqlite3_} $funcname]} { + if {[regexp {^sqlite3[a-z]*_} $funcname]} { set line SQLITE_API append line " " [string trim $rettype] if {[string index $rettype end] ne "*"} { append line " " } - if {[lsearch -exact $cdecllist $funcname] >= 0} { - append line SQLITE_CDECL - } else { - append line SQLITE_APICALL + if {$useapicall} { + if {[lsearch -exact $cdecllist $funcname] >= 0} { + append line SQLITE_CDECL " " + } else { + append line SQLITE_APICALL " " + } } - append line " " $funcname $rest + append line $funcname $rest puts $out $line } else { puts $out "SQLITE_PRIVATE $line" } } elseif {[regexp $varpattern $line all varname]} { @@ -283,10 +292,11 @@ mutex_noop.c mutex_unix.c mutex_w32.c malloc.c printf.c + treeview.c random.c threads.c utf.c util.c hash.c @@ -311,11 +321,10 @@ vdbeapi.c vdbetrace.c vdbe.c vdbeblob.c vdbesort.c - journal.c memjournal.c walker.c resolve.c expr.c @@ -337,10 +346,12 @@ table.c trigger.c update.c vacuum.c vtab.c + wherecode.c + whereexpr.c where.c parse.c tokenize.c Index: tool/mksqlite3c.tcl ================================================================== --- tool/mksqlite3c.tcl +++ tool/mksqlite3c.tcl @@ -1,19 +1,19 @@ #!/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 +# 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 +# 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: # @@ -26,16 +26,19 @@ # from in this file. The version number is needed to generate the header # comment of the amalgamation. # set addstatic 1 set linemacros 0 +set useapicall 0 for {set i 0} {$i<[llength $argv]} {incr i} { set x [lindex $argv $i] if {[regexp {^-+nostatic$} $x]} { set addstatic 0 } elseif {[regexp {^-+linemacros} $x]} { set linemacros 1 + } elseif {[regexp {^-+useapicall} $x]} { + set useapicall 1 } else { error "unknown command-line option: $x" } } set in [open tsrc/sqlite3.h] @@ -57,20 +60,20 @@ 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 +** 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 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 @@ -83,11 +86,11 @@ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif} } -# These are the header files used by SQLite. The first time any of these +# 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 @@ -110,11 +113,10 @@ parse.h pcache.h pragma.h rtree.h sqlite3session.h - sqlite3ext.h sqlite3.h sqlite3ext.h sqlite3rbu.h sqliteicu.h sqliteInt.h @@ -164,11 +166,12 @@ # Read the source file named $filename and write it into the # sqlite3.c output file. If any #include statements are seen, # process them appropriately. # proc copy_file {filename} { - global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros + global seen_hdr available_hdr varonly_hdr cdecllist out + global addstatic linemacros useapicall 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] @@ -227,16 +230,18 @@ set line SQLITE_API append line " " [string trim $rettype] if {[string index $rettype end] ne "*"} { append line " " } - if {[lsearch -exact $cdecllist $funcname] >= 0} { - append line SQLITE_CDECL - } else { - append line SQLITE_STDCALL + if {$useapicall} { + if {[lsearch -exact $cdecllist $funcname] >= 0} { + append line SQLITE_CDECL " " + } else { + append line SQLITE_APICALL " " + } } - append line " " $funcname $rest + append line $funcname $rest puts $out $line } else { puts $out "SQLITE_PRIVATE $line" } } elseif {[regexp $varpattern $line all varname]} { Index: tool/mksqlite3h.tcl ================================================================== --- tool/mksqlite3h.tcl +++ tool/mksqlite3h.tcl @@ -8,21 +8,23 @@ # 3) The manifest file from the fossil SCM. This gives use the date. # 4) The manifest.uuid file from the fossil SCM. This gives the SHA1 hash. # # Run this script by specifying the root directory of the source tree # on the command-line. -# +# # This script performs processing on src/sqlite.h.in. It: # # 1) Adds SQLITE_EXTERN in front of the declaration of global variables, # 2) Adds SQLITE_API in front of the declaration of API functions, -# 3) Replaces the string --VERS-- with the current library version, +# 3) Replaces the string --VERS-- with the current library version, # formatted as a string (e.g. "3.6.17"), and # 4) Replaces the string --VERSION-NUMBER-- with current library version, # formatted as an integer (e.g. "3006017"). -# 5) Replaces the string --SOURCE-ID-- with the date and time and sha1 +# 5) Replaces the string --SOURCE-ID-- with the date and time and sha1 # hash of the fossil-scm manifest for the source tree. +# 6) Adds the SQLITE_CALLBACK calling convention macro in front of all +# callback declarations. # # This script outputs to stdout. # # Example usage: # @@ -31,10 +33,18 @@ # Get the source tree root directory from the command-line # set TOP [lindex $argv 0] + +# Enable use of SQLITE_APICALL macros at the right points? +# +set useapicall 0 + +if {[lsearch -regexp [lrange $argv 1 end] {^-+useapicall}] != -1} { + set useapicall 1 +} # Get the SQLite version number (ex: 3.6.18) from the $TOP/VERSION file. # set in [open $TOP/VERSION] set zVersion [string trim [read $in]] @@ -94,18 +104,18 @@ set in [open $file] if {![regexp {sqlite\.h\.in} $file]} { puts "/******** Begin file [file tail $file] *********/" } while {![eof $in]} { - + set line [gets $in] # File sqlite3rtree.h contains a line "#include ". Omit this # line when copying sqlite3rtree.h into sqlite3.h. # if {[string match {*#include*[<"]sqlite3.h[>"]*} $line]} continue - + regsub -- --VERS-- $line $zVersion line regsub -- --VERSION-NUMBER-- $line $nVersion line regsub -- --SOURCE-ID-- $line "$zDate $zUuid" line if {[regexp $varpattern $line] && ![regexp {^ *typedef} $line]} { @@ -115,20 +125,27 @@ set line SQLITE_API append line " " [string trim $rettype] if {[string index $rettype end] ne "*"} { append line " " } - if {[lsearch -exact $cdecllist $funcname] >= 0} { - append line SQLITE_CDECL - } else { - append line SQLITE_STDCALL + if {$useapicall} { + if {[lsearch -exact $cdecllist $funcname] >= 0} { + append line SQLITE_CDECL " " + } else { + append line SQLITE_APICALL " " + } } - append line " " $funcname $rest + append line $funcname $rest } } + if {$useapicall} { + set line [string map [list (*sqlite3_syscall_ptr) \ + "(SQLITE_SYSAPI *sqlite3_syscall_ptr)"] $line] + regsub {\(\*} $line {(SQLITE_CALLBACK *} line + } puts $line } close $in if {![regexp {sqlite\.h\.in} $file]} { puts "/******** End of [file tail $file] *********/" } } Index: tool/sqldiff.c ================================================================== --- tool/sqldiff.c +++ tool/sqldiff.c @@ -1177,13 +1177,12 @@ strPrintf(pSql, ", 0, "); /* Set ota_control to 0 for an insert */ strPrintfArray(pSql, ", ", "NULL", azCol, -1); strPrintf(pSql, " FROM aux.%Q AS n WHERE NOT EXISTS (\n", zTab); strPrintf(pSql, " SELECT 1 FROM ", zTab); strPrintf(pSql, " main.%Q AS o WHERE ", zTab); - strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK); - strPrintf(pSql, "\n) AND "); - strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK); + strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); + strPrintf(pSql, "\n)"); /* Deleted rows: */ strPrintf(pSql, "\nUNION ALL\nSELECT "); strPrintfArray(pSql, ", ", "%s", azCol, nPK); if( azCol[nPK] ){ @@ -1193,13 +1192,12 @@ strPrintf(pSql, ", 1, "); /* Set ota_control to 1 for a delete */ strPrintfArray(pSql, ", ", "NULL", azCol, -1); strPrintf(pSql, " FROM main.%Q AS n WHERE NOT EXISTS (\n", zTab); strPrintf(pSql, " SELECT 1 FROM ", zTab); strPrintf(pSql, " aux.%Q AS o WHERE ", zTab); - strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK); - strPrintf(pSql, "\n) AND "); - strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK); + strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); + strPrintf(pSql, "\n) "); /* Updated rows. If all table columns are part of the primary key, there ** can be no updates. In this case this part of the compound SELECT can ** be omitted altogether. */ if( azCol[nPK] ){ @@ -1226,11 +1224,11 @@ strPrintfArray(pSql, " ,\n", " CASE WHEN n.%s IS o.%s THEN NULL ELSE o.%s END", &azCol[nPK], -1 ); strPrintf(pSql, "\nFROM main.%Q AS o, aux.%Q AS n\nWHERE ", zTab, zTab); - strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK); + strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); strPrintf(pSql, " AND ota_control LIKE '%%x%%'"); } /* Now add an ORDER BY clause to sort everything by PK. */ strPrintf(pSql, "\nORDER BY ");