SQLite

Check-in [b243007525]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge trunk changes into this branch.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | fts5-locale
Files: files | file ages | folders
SHA3-256: b243007525a825b3daf8aa9bb2d3088efb853bd8b7c9ea3c0924fde193eb5c44
User & Date: dan 2024-08-10 20:03:01.148
Context
2024-08-12
11:13
Update the auxiliary function API to include xTokenize_x2() instead of xSetLocale(). (check-in: f7d56a1f21 user: dan tags: fts5-locale)
2024-08-10
20:03
Merge trunk changes into this branch. (check-in: b243007525 user: dan tags: fts5-locale)
19:57
Prevent the fts5 xPhraseNext() or xPhraseFirst() APIs from returning an out-of-range column number, even if the database is corrupt. (check-in: d4014c87ba user: dan tags: trunk)
19:18
Fix an uninitialized variable in fts5_tcl.c. (check-in: 924d3467ce user: dan tags: fts5-locale)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#
TCLSH_CMD = @TCLSH_CMD@

# Where do we want to install the tcl plugin
#
TCLLIBDIR = @TCLLIBDIR@

# The suffix used on shared libraries.  Ex:  ".dll", ".so", ".dylib"
#
SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@

# If gcov support was enabled by the configure script, add the appropriate
# flags here.  It's not always as easy as just having the user add the right
# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
# Supposedly GCC does the right thing if you use --coverage, but in
# practice it still fails.  See:
#







<
<
<
<







117
118
119
120
121
122
123




124
125
126
127
128
129
130
#
TCLSH_CMD = @TCLSH_CMD@

# Where do we want to install the tcl plugin
#
TCLLIBDIR = @TCLLIBDIR@





# If gcov support was enabled by the configure script, add the appropriate
# flags here.  It's not always as easy as just having the user add the right
# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
# Supposedly GCC does the right thing if you use --coverage, but in
# practice it still fails.  See:
#
1554
1555
1556
1557
1558
1559
1560

1561
1562
1563
1564
1565
























1566
1567
1568
1569
1570
1571
1572
	$(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir)
	$(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
	$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)

pkgIndex.tcl:
	echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@

tcl_install:	lib_install libtclsqlite3.la pkgIndex.tcl
	$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
	$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
	rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
	$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)

























clean:
	rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps
	rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
	rm -f mkkeywordhash$(BEXE) keywordhash.h







>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
	$(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir)
	$(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
	$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)

pkgIndex.tcl:
	echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@

tcl_install:	lib_install libtclsqlite3.la pkgIndex.tcl
	$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
	$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
	rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
	$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)

# Build the SQLite TCL extension in a way that make it compatible
# with whatever version of TCL is running as $TCLSH_CMD, possibly defined
# by --with-tclsh=
#
tclextension:	tclsqlite3.c
	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --build-only --cc $(CC) $(CFLAGS) $(OPT_FEATURE_FLAGS) $(OPTS)

# Install the SQLite TCL extension in a way that is appropriate for $TCLSH_CMD
# to find it.
#
tclextension-install:	tclsqlite3.c
	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --cc $(CC) $(CFLAGS) $(OPT_FEATURE_FLAGS) $(OPTS)

# Install the SQLite TCL extension that is used by $TCLSH_CMD
#
tclextension-uninstall: 
	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --uninstall

# List all installed the SQLite TCL extension that is are accessible
# by $TCLSH_CMD, included prior versions.
#
tclextension-list: 
	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --info

clean:
	rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps
	rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
	rm -f mkkeywordhash$(BEXE) keywordhash.h
Changes to Makefile.msc.
1816
1817
1818
1819
1820
1821
1822













1823
1824
1825
1826
1827
1828
1829
	for /F %%V in ('type "$(TOP)\VERSION"') do ( \
		echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] sqlite3] \
			| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact @version@ %%V > pkgIndex.tcl \
	)

$(SQLITE3TCLDLL):	libtclsqlite3.lib $(LIBRESOBJS) tclsqlite3.def pkgIndex.tcl
	$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:tclsqlite3.def /OUT:$@ libtclsqlite3.lib $(LIBRESOBJS) $(LTLIBS) $(TLIBS)













# <</mark>>

$(SQLITE3DLL):	$(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
	$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)

# <<block2>>
sqlite3.def:	libsqlite3.lib







>
>
>
>
>
>
>
>
>
>
>
>
>







1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
	for /F %%V in ('type "$(TOP)\VERSION"') do ( \
		echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] sqlite3] \
			| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact @version@ %%V > pkgIndex.tcl \
	)

$(SQLITE3TCLDLL):	libtclsqlite3.lib $(LIBRESOBJS) tclsqlite3.def pkgIndex.tcl
	$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:tclsqlite3.def /OUT:$@ libtclsqlite3.lib $(LIBRESOBJS) $(LTLIBS) $(TLIBS)

tclextension:	$(SQLITE3TCLDLL)

tclextension-install:	$(SQLITE3TCLDLL)
	$(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --install-only

tclextension-uninstall:
	$(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --uninstall

tclextension-list:
	$(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --info


# <</mark>>

$(SQLITE3DLL):	$(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
	$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)

# <<block2>>
sqlite3.def:	libsqlite3.lib
Changes to autoconf/tea/tclconfig/tcl.m4.
Changes to autoconf/tea/win/rules.vc.
704
705
706
707
708
709
710
711
!message *** Optional defines are '$(OPTDEFINES)'
!message *** Compiler version $(VCVER). Target machine is $(MACHINE)
!message *** Host architecture is $(NATIVE_ARCH)
!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)'
!message *** Link options '$(LINKERFLAGS)'

!endif








<
704
705
706
707
708
709
710

!message *** Optional defines are '$(OPTDEFINES)'
!message *** Compiler version $(VCVER). Target machine is $(MACHINE)
!message *** Host architecture is $(NATIVE_ARCH)
!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)'
!message *** Link options '$(LINKERFLAGS)'

!endif

Changes to configure.
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808




809
810
811
812
813
814
815
USE_AMALGAMATION
TARGET_DEBUG
TARGET_HAVE_LINENOISE
TARGET_HAVE_EDITLINE
TARGET_HAVE_READLINE
TARGET_READLINE_INC
TARGET_READLINE_LIBS
HAVE_TCL
TCL_SHLIB_SUFFIX
TCL_STUB_LIB_SPEC
TCL_STUB_LIB_FLAG
TCL_STUB_LIB_FILE
TCL_LIB_SPEC
TCL_LIB_FLAG
TCL_LIB_FILE
TCL_INCLUDE_SPEC
TCL_SRC_DIR
TCL_BIN_DIR
TCL_VERSION
TARGET_EXEEXT
SQLITE_OS_WIN
SQLITE_OS_UNIX
BUILD_EXEEXT
TEMP_STORE
ALLOWRELEASE
SQLITE_THREADSAFE
BUILD_CC
HAVE_WASI_SDK
RELEASE
VERSION
program_prefix
TCLLIBDIR




TCLSH_CMD
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
CPP
OTOOL64
OTOOL







<
<
<
<
<
<
<
<
<
<
<
<













>
>
>
>







777
778
779
780
781
782
783












784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
USE_AMALGAMATION
TARGET_DEBUG
TARGET_HAVE_LINENOISE
TARGET_HAVE_EDITLINE
TARGET_HAVE_READLINE
TARGET_READLINE_INC
TARGET_READLINE_LIBS












TARGET_EXEEXT
SQLITE_OS_WIN
SQLITE_OS_UNIX
BUILD_EXEEXT
TEMP_STORE
ALLOWRELEASE
SQLITE_THREADSAFE
BUILD_CC
HAVE_WASI_SDK
RELEASE
VERSION
program_prefix
TCLLIBDIR
HAVE_TCL
TCL_STUB_LIB_SPEC
TCL_LIB_SPEC
TCL_INCLUDE_SPEC
TCLSH_CMD
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
CPP
OTOOL64
OTOOL
890
891
892
893
894
895
896


897
898
899
900
901
902
903
904
905
906
907
908
909
enable_shared
enable_static
with_pic
enable_fast_install
with_gnu_ld
enable_libtool_lock
enable_largefile


with_wasi_sdk
enable_threadsafe
enable_releasemode
enable_tempstore
enable_tcl
with_tcl
enable_editline
enable_readline
with_readline_lib
with_readline_inc
with_linenoise
enable_debug
enable_amalgamation







>
>




<
<







882
883
884
885
886
887
888
889
890
891
892
893
894


895
896
897
898
899
900
901
enable_shared
enable_static
with_pic
enable_fast_install
with_gnu_ld
enable_libtool_lock
enable_largefile
with_tclsh
with_tcl
with_wasi_sdk
enable_threadsafe
enable_releasemode
enable_tempstore


enable_editline
enable_readline
with_readline_lib
with_readline_inc
with_linenoise
enable_debug
enable_amalgamation
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
                          optimize for fast installation [default=yes]
  --disable-libtool-lock  avoid locking (might break parallel builds)
  --disable-largefile     omit support for large files
  --disable-threadsafe    Disable mutexing
  --enable-releasemode    Support libtool link to release mode
  --enable-tempstore      Use an in-ram database for temporary tables
                          (never,no,yes,always)
  --disable-tcl           do not build TCL extension
  --enable-editline       enable BSD editline support
  --disable-readline      disable readline support
  --enable-debug          enable debugging & verbose explain
  --disable-amalgamation  Disable the amalgamation and instead build all files
                          separately
  --disable-load-extension
                          Disable loading of external extensions







<







1543
1544
1545
1546
1547
1548
1549

1550
1551
1552
1553
1554
1555
1556
                          optimize for fast installation [default=yes]
  --disable-libtool-lock  avoid locking (might break parallel builds)
  --disable-largefile     omit support for large files
  --disable-threadsafe    Disable mutexing
  --enable-releasemode    Support libtool link to release mode
  --enable-tempstore      Use an in-ram database for temporary tables
                          (never,no,yes,always)

  --enable-editline       enable BSD editline support
  --disable-readline      disable readline support
  --enable-debug          enable debugging & verbose explain
  --disable-amalgamation  Disable the amalgamation and instead build all files
                          separately
  --disable-load-extension
                          Disable loading of external extensions
1579
1580
1581
1582
1583
1584
1585


1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-pic              try to use only PIC/non-PIC objects [default=use
                          both]
  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]


  --with-wasi-sdk=DIR     directory containing the WASI SDK. Triggers
                          cross-compile to WASM.
  --with-tcl=DIR          directory containing tcl configuration
                          (tclConfig.sh)
  --with-readline-lib     specify readline library
  --with-readline-inc     specify readline include paths
  --with-linenoise=DIR    source directory for linenoise library

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags







>
>


<
<







1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580


1581
1582
1583
1584
1585
1586
1587

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-pic              try to use only PIC/non-PIC objects [default=use
                          both]
  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
  --with-tclsh=PATHNAME   full pathname of a tclsh to use
  --with-tcl=DIR          directory containing (tclConfig.sh)
  --with-wasi-sdk=DIR     directory containing the WASI SDK. Triggers
                          cross-compile to WASM.


  --with-readline-lib     specify readline library
  --with-readline-inc     specify readline include paths
  --with-linenoise=DIR    source directory for linenoise library

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
$as_echo_n "checking the name lister ($NM) interface... " >&6; }
if ${lt_cv_nm_interface+:} false; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_nm_interface="BSD nm"
  echo "int some_variable = 0;" > conftest.$ac_ext
  (eval echo "\"\$as_me:3948: $ac_compile\"" >&5)
  (eval "$ac_compile" 2>conftest.err)
  cat conftest.err >&5
  (eval echo "\"\$as_me:3951: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
  cat conftest.err >&5
  (eval echo "\"\$as_me:3954: output\"" >&5)
  cat conftest.out >&5
  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
    lt_cv_nm_interface="MS dumpbin"
  fi
  rm -f conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5







|


|


|







3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
$as_echo_n "checking the name lister ($NM) interface... " >&6; }
if ${lt_cv_nm_interface+:} false; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_nm_interface="BSD nm"
  echo "int some_variable = 0;" > conftest.$ac_ext
  (eval echo "\"\$as_me:3939: $ac_compile\"" >&5)
  (eval "$ac_compile" 2>conftest.err)
  cat conftest.err >&5
  (eval echo "\"\$as_me:3942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
  cat conftest.err >&5
  (eval echo "\"\$as_me:3945: output\"" >&5)
  cat conftest.out >&5
  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
    lt_cv_nm_interface="MS dumpbin"
  fi
  rm -f conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
	;;
    esac
  fi
  rm -rf conftest*
  ;;
*-*-irix6*)
  # Find out which ABI we are using.
  echo '#line 5160 "configure"' > conftest.$ac_ext
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
    if test "$lt_cv_prog_gnu_ld" = yes; then
      case `/usr/bin/file conftest.$ac_objext` in







|







5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
	;;
    esac
  fi
  rm -rf conftest*
  ;;
*-*-irix6*)
  # Find out which ABI we are using.
  echo '#line 5151 "configure"' > conftest.$ac_ext
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
    if test "$lt_cv_prog_gnu_ld" = yes; then
      case `/usr/bin/file conftest.$ac_objext` in
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   # The option is referenced via a variable to avoid confusing sed.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:6685: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>conftest.err)
   ac_status=$?
   cat conftest.err >&5
   echo "$as_me:6689: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s "$ac_outfile"; then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings other than the usual output.
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_rtti_exceptions=yes







|



|







6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   # The option is referenced via a variable to avoid confusing sed.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:6676: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>conftest.err)
   ac_status=$?
   cat conftest.err >&5
   echo "$as_me:6680: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s "$ac_outfile"; then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings other than the usual output.
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_rtti_exceptions=yes
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   # The option is referenced via a variable to avoid confusing sed.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:7024: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>conftest.err)
   ac_status=$?
   cat conftest.err >&5
   echo "$as_me:7028: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s "$ac_outfile"; then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings other than the usual output.
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_pic_works=yes







|



|







7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   # The option is referenced via a variable to avoid confusing sed.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:7015: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>conftest.err)
   ac_status=$?
   cat conftest.err >&5
   echo "$as_me:7019: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s "$ac_outfile"; then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings other than the usual output.
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_pic_works=yes
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:7129: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:7133: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then







|



|







7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:7120: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:7124: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:7184: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:7188: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then







|



|







7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:7175: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:7179: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
9557
9558
9559
9560
9561
9562
9563
9564
9565
9566
9567
9568
9569
9570
9571
else
  	  if test "$cross_compiling" = yes; then :
  lt_cv_dlopen_self=cross
else
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
  lt_status=$lt_dlunknown
  cat > conftest.$ac_ext <<_LT_EOF
#line 9564 "configure"
#include "confdefs.h"

#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif

#include <stdio.h>







|







9548
9549
9550
9551
9552
9553
9554
9555
9556
9557
9558
9559
9560
9561
9562
else
  	  if test "$cross_compiling" = yes; then :
  lt_cv_dlopen_self=cross
else
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
  lt_status=$lt_dlunknown
  cat > conftest.$ac_ext <<_LT_EOF
#line 9555 "configure"
#include "confdefs.h"

#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif

#include <stdio.h>
9653
9654
9655
9656
9657
9658
9659
9660
9661
9662
9663
9664
9665
9666
9667
else
  	  if test "$cross_compiling" = yes; then :
  lt_cv_dlopen_self_static=cross
else
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
  lt_status=$lt_dlunknown
  cat > conftest.$ac_ext <<_LT_EOF
#line 9660 "configure"
#include "confdefs.h"

#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif

#include <stdio.h>







|







9644
9645
9646
9647
9648
9649
9650
9651
9652
9653
9654
9655
9656
9657
9658
else
  	  if test "$cross_compiling" = yes; then :
  lt_cv_dlopen_self_static=cross
else
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
  lt_status=$lt_dlunknown
  cat > conftest.$ac_ext <<_LT_EOF
#line 9651 "configure"
#include "confdefs.h"

#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif

#include <stdio.h>
10310
10311
10312
10313
10314
10315
10316



10317




10318
10319




10320

10321
10322
10323
10324
10325
10326
10327
10328

#########
# By default, we use the amalgamation (this may be changed below...)
#
USE_AMALGAMATION=1

#########



# See whether we can run specific tclsh versions known to work well;




# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?




#

for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_TCLSH_CMD+:} false; then :
  $as_echo_n "(cached) " >&6







>
>
>
|
>
>
>
>
|
|
>
>
>
>
|
>
|







10301
10302
10303
10304
10305
10306
10307
10308
10309
10310
10311
10312
10313
10314
10315
10316
10317
10318
10319
10320
10321
10322
10323
10324
10325
10326
10327
10328
10329
10330
10331

#########
# By default, we use the amalgamation (this may be changed below...)
#
USE_AMALGAMATION=1

#########
# Figure out all the name of a working tclsh and parameters needed to compile against Tcl.
# The --with-tcl= and/or --with-tclsh= configuration arguments might be useful for this.
#

# Check whether --with-tclsh was given.
if test "${with_tclsh+set}" = set; then :
  withval=$with_tclsh;
fi


# Check whether --with-tcl was given.
if test "${with_tcl+set}" = set; then :
  withval=$with_tcl;
fi

if test x"${with_tclsh}" == x -a x"${with_tcl}" == x; then
  for ac_prog in tclsh8.6 tclsh tclsh9.0
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_TCLSH_CMD+:} false; then :
  $as_echo_n "(cached) " >&6
10357
10358
10359
10360
10361
10362
10363










































































10364
10365
10366

10367
10368
10369



10370
10371
10372
10373

10374
10375
10376
10377
10378
10379
10380
10381
10382
fi


  test -n "$TCLSH_CMD" && break
done
test -n "$TCLSH_CMD" || TCLSH_CMD="none"











































































if test "$TCLSH_CMD" = "none"; then
  # If we can't find a local tclsh, then building the amalgamation will fail.
  # We act as though --disable-amalgamation has been used.

  echo "Warning: can't find tclsh - defaulting to non-amalgamation build."
  USE_AMALGAMATION=0
  TCLSH_CMD="tclsh"



fi




if test "x${TCLLIBDIR+set}" != "xset" ; then
  TCLLIBDIR='$(libdir)'
  for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
    if test -d $i ; then
      TCLLIBDIR=$i
      break
    fi
  done
  TCLLIBDIR="${TCLLIBDIR}/sqlite3"







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



>
|


>
>
>




>

<







10360
10361
10362
10363
10364
10365
10366
10367
10368
10369
10370
10371
10372
10373
10374
10375
10376
10377
10378
10379
10380
10381
10382
10383
10384
10385
10386
10387
10388
10389
10390
10391
10392
10393
10394
10395
10396
10397
10398
10399
10400
10401
10402
10403
10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415
10416
10417
10418
10419
10420
10421
10422
10423
10424
10425
10426
10427
10428
10429
10430
10431
10432
10433
10434
10435
10436
10437
10438
10439
10440
10441
10442
10443
10444
10445
10446
10447
10448
10449
10450
10451
10452
10453
10454
10455
10456

10457
10458
10459
10460
10461
10462
10463
fi


  test -n "$TCLSH_CMD" && break
done
test -n "$TCLSH_CMD" || TCLSH_CMD="none"

  with_tclsh=${TCLSH_CMD}
fi
if test x"${with_tclsh}" != x -a x"${with_tclsh}" != xnone; then
  TCLSH_CMD=${with_tclsh}
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: using tclsh at \"$TCLSH_CMD\"" >&5
$as_echo "using tclsh at \"$TCLSH_CMD\"" >&6; }
  with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
  if test x"${with_tcl}" != x; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}" >&5
$as_echo "$TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}" >&6; }
  else
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $TCLSH_CMD is unable to recommend a tclConfig.sh" >&5
$as_echo "$as_me: WARNING: $TCLSH_CMD is unable to recommend a tclConfig.sh" >&2;}
  fi
fi
if test x"${with_tcl}" != x; then
  if test -r ${with_tcl}/tclConfig.sh; then
    tclconfig="${with_tcl}/tclConfig.sh"
  else
    for i in tcl8.6 tcl9.0 lib; do
      if test -r ${with_tcl}/$i/tclConfig.sh; then
        tclconfig=${with_tcl}/$i/tclConfig.sh
        break
      fi
    done
  fi
  if test ! -r "${tclconfig}"; then
    as_fn_error $? "no tclConfig.sh file found under ${with_tcl}" "$LINENO" 5
  fi
else
  # If we have not yet found a tclConfig.sh file, look in $libdir whic is
  # set automatically by autoconf or by the --prefix command-line option.
  # See https://sqlite.org/forum/forumpost/e04e693439a22457
  libdir=${prefix}/lib
  if test -r ${libdir}/tclConfig.sh; then
    tclconfig=${libdir}/tclConfig.sh
  else
    for i in tcl8.6 tcl9.0 lib; do
      if test -r ${libdir}/$i/tclConfig.sh; then
        tclconfig=${libdir}/$i/tclConfig.sh
        break
      fi
    done
  fi
  if test ! -r "${tclconfig}"; then
    as_fn_error $? "cannot find a usable tclConfig.sh file.
      Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
      SQLite does not use TCL internally, but TCL is required to build SQLite
      from canonical sources and TCL is required for testing." "$LINENO" 5
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: loading TCL configuration from ${tclconfig}" >&5
$as_echo "loading TCL configuration from ${tclconfig}" >&6; }
. ${tclconfig}



# There are lots of other configuration variables that are provided by the
# tclConfig.sh file and that could be included here.  But as of right now,
# TCL_LIB_SPEC is the only what that the Makefile uses.

if test x"$TCLSH_CMD" == x; then
  TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
  if test ! -x ${TCLSH_CMD}; then
    TCLSH_CMD_2=${TCL_EXEC_PREFIX}/bin/tclsh
    if test ! -x ${TCLSH_CMD_2}; then
      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find a usable tclsh at either ${TCLSH_CMD} or ${TCLSH_CMD_2}" >&5
$as_echo "$as_me: WARNING: cannot find a usable tclsh at either ${TCLSH_CMD} or ${TCLSH_CMD_2}" >&2;}
      TCLSH_CMD=none
    else
      TCLSH_CMD=${TCLSH_CMD_2}
    fi
  fi
fi
if test "$TCLSH_CMD" = "none"; then
  # If we can't find a local tclsh, then building the amalgamation will fail.
  # We act as though --disable-amalgamation has been used.
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Warning: can't find tclsh - defaulting to non-amalgamation build." >&5
$as_echo "$as_me: WARNING: Warning: can't find tclsh - defaulting to non-amalgamation build." >&2;}
  USE_AMALGAMATION=0
  TCLSH_CMD="tclsh"
  HAVE_TCL=0
else
  HAVE_TCL=1
fi




if test "x${TCLLIBDIR+set}" != "xset" ; then

  for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
    if test -d $i ; then
      TCLLIBDIR=$i
      break
    fi
  done
  TCLLIBDIR="${TCLLIBDIR}/sqlite3"
10764
10765
10766
10767
10768
10769
10770
10771
10772
10773
10774
10775
10776
10777
10778
10779
10780
10781
10782
10783
10784
10785
10786
10787
10788
10789
10790
10791
10792
10793
10794
10795
10796
10797
10798
10799
10800
10801
10802
10803
10804
10805
10806
10807
10808
10809
10810
10811
10812
10813
10814
10815
10816
10817
10818
10819
10820
10821
10822
10823
10824
10825
10826
10827
10828
10829
10830
10831
10832
10833
10834
10835
10836
10837
10838
10839
10840
10841
10842
10843
10844
10845
10846
10847
10848
10849
10850
10851
10852
10853
10854
10855
10856
10857
10858
10859
10860
10861
10862
10863
10864
10865
10866
10867
10868
10869
10870
10871
10872
10873
10874
10875
10876
10877
10878
10879
10880
10881
10882
10883
10884
10885
10886
10887
10888
10889
10890
10891
10892
10893
10894
10895
10896
10897
10898
10899
10900
10901
10902
10903
10904
10905
10906
10907
10908
10909
10910
10911
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921
10922
10923
10924
10925
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946
10947
10948
10949
10950
10951
10952
10953
10954
10955
10956
10957
10958
10959
10960
10961
10962
10963
10964
10965
10966
10967
10968
10969
10970
10971
10972
10973
10974
10975
10976
10977
10978
10979
10980
10981
10982
10983
10984
  CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
fi






##########
# Figure out all the parameters needed to compile against Tcl.
#
# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
# macros in the in the tcl.m4 file of the standard TCL distribution.
# Those macros could not be used directly since we have to make some
# minor changes to accomodate systems that do not have TCL installed.
#
# Check whether --enable-tcl was given.
if test "${enable_tcl+set}" = set; then :
  enableval=$enable_tcl; use_tcl=$enableval
else
  use_tcl=yes
fi

if test "${use_tcl}" = "yes" ; then

# Check whether --with-tcl was given.
if test "${with_tcl+set}" = set; then :
  withval=$with_tcl; with_tclconfig=${withval}
fi

  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5
$as_echo_n "checking for Tcl configuration... " >&6; }
  if ${ac_cv_c_tclconfig+:} false; then :
  $as_echo_n "(cached) " >&6
else

    # First check to see if --with-tcl was specified.
    if test x"${with_tclconfig}" != x ; then
      if test -f "${with_tclconfig}/tclConfig.sh" ; then
        ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
      else
        as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5
      fi
    fi

    # Start autosearch by asking tclsh
    if test x"${ac_cv_c_tclconfig}" = x ; then
      if test x"$cross_compiling" = xno; then
        for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}`
        do
          if test -f "$i/tclConfig.sh" ; then
            ac_cv_c_tclconfig="$i"
            break
          fi
        done
      fi
    fi

    # On ubuntu 14.10, $auto_path on tclsh is not quite correct.
    # So try again after applying corrections.
    if test x"${ac_cv_c_tclconfig}" = x ; then
      if test x"$cross_compiling" = xno; then
        for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'`
        do
          if test -f "$i/tclConfig.sh" ; then
            ac_cv_c_tclconfig="$i"
            break
          fi
        done
      fi
    fi

    # Recent versions of Xcode on Macs hid the tclConfig.sh file
    # in a strange place.
    if test x"${ac_cv_c_tclconfig}" = x ; then
      if test x"$cross_compiling" = xno; then
        for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib
        do
          if test -f "$i/tclConfig.sh" ; then
            ac_cv_c_tclconfig="$i"
            break
          fi
        done
      fi
    fi

    # then check for a private Tcl installation
    if test x"${ac_cv_c_tclconfig}" = x ; then
      for i in \
            ../tcl \
            `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
            `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \
            `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \
            ../../tcl \
            `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
            `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \
            `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \
            ../../../tcl \
            `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
            `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \
            `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null`
      do
        if test -f "$i/unix/tclConfig.sh" ; then
          ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
          break
        fi
      done
    fi

    # check in a few common install locations
    if test x"${ac_cv_c_tclconfig}" = x ; then
      for i in \
            `ls -d ${libdir} 2>/dev/null` \
            `ls -d /usr/local/lib 2>/dev/null` \
            `ls -d /usr/contrib/lib 2>/dev/null` \
            `ls -d /usr/lib 2>/dev/null`
      do
        if test -f "$i/tclConfig.sh" ; then
           ac_cv_c_tclconfig=`(cd $i; pwd)`
           break
        fi
      done
    fi

    # check in a few other private locations
    if test x"${ac_cv_c_tclconfig}" = x ; then
      for i in \
         ${srcdir}/../tcl \
         `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
         `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \
         `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null`
      do
        if test -f "$i/unix/tclConfig.sh" ; then
          ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
          break
        fi
      done
    fi

fi


  if test x"${ac_cv_c_tclconfig}" = x ; then
    use_tcl=no
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find Tcl configuration definitions" >&5
$as_echo "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5
$as_echo "$as_me: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5
$as_echo "$as_me: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&2;}
  else
    TCL_BIN_DIR=${ac_cv_c_tclconfig}
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $TCL_BIN_DIR/tclConfig.sh" >&5
$as_echo "found $TCL_BIN_DIR/tclConfig.sh" >&6; }

    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5
$as_echo_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh... " >&6; }
    if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
      { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5
$as_echo "loading" >&6; }
      . $TCL_BIN_DIR/tclConfig.sh
    else
      { $as_echo "$as_me:${as_lineno-$LINENO}: result: file not found" >&5
$as_echo "file not found" >&6; }
    fi

    #
    # If the TCL_BIN_DIR is the build directory (not the install directory),
    # then set the common variable name to the value of the build variables.
    # For example, the variable TCL_LIB_SPEC will be set to the value
    # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
    # instead of TCL_BUILD_LIB_SPEC since it will work with both an
    # installed and uninstalled version of Tcl.
    #

    if test -f $TCL_BIN_DIR/Makefile ; then
      TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
      TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
      TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
    fi

    #
    # eval is required to do the TCL_DBGX substitution
    #

    eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
    eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
    eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""

    eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
    eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
    eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""














  fi
fi
if test "${use_tcl}" = "no" ; then
  HAVE_TCL=""
else
  HAVE_TCL=1
fi


##########
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
#
TARGET_READLINE_LIBS=""
TARGET_READLINE_INC=""







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







10845
10846
10847
10848
10849
10850
10851















































































































































































































10852
10853
10854
10855
10856
10857
10858
  CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
fi





















































































































































































































##########
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
#
TARGET_READLINE_LIBS=""
TARGET_READLINE_INC=""
Changes to configure.ac.
112
113
114
115
116
117
118
119
120
121
122



123





































































124
125
126
127
128
129



130
131

132
133
134
135
136
137
138
139
140
141
142

#########
# By default, we use the amalgamation (this may be changed below...)
#
USE_AMALGAMATION=1

#########
# See whether we can run specific tclsh versions known to work well;
# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?
# 



AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.7 tclsh8.6 tclsh8.5 tclsh], none)





































































if test "$TCLSH_CMD" = "none"; then
  # If we can't find a local tclsh, then building the amalgamation will fail.
  # We act as though --disable-amalgamation has been used.
  echo "Warning: can't find tclsh - defaulting to non-amalgamation build."
  USE_AMALGAMATION=0
  TCLSH_CMD="tclsh"



fi
AC_SUBST(TCLSH_CMD)


AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])
if test "x${TCLLIBDIR+set}" != "xset" ; then
  TCLLIBDIR='$(libdir)'
  for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
    if test -d $i ; then
      TCLLIBDIR=$i
      break
    fi
  done
  TCLLIBDIR="${TCLLIBDIR}/sqlite3"







|
|
<
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|


>
>
>


>



<







112
113
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216

#########
# By default, we use the amalgamation (this may be changed below...)
#
USE_AMALGAMATION=1

#########
# Figure out all the name of a working tclsh and parameters needed to compile against Tcl.
# The --with-tcl= and/or --with-tclsh= configuration arguments might be useful for this.

#
AC_ARG_WITH(tclsh, AS_HELP_STRING([--with-tclsh=PATHNAME],[full pathname of a tclsh to use]))
AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl=DIR],[directory containing (tclConfig.sh)]))
if test x"${with_tclsh}" == x -a x"${with_tcl}" == x; then
  AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh tclsh9.0],none)
  with_tclsh=${TCLSH_CMD}
fi
if test x"${with_tclsh}" != x -a x"${with_tclsh}" != xnone; then
  TCLSH_CMD=${with_tclsh}
  AC_MSG_RESULT([using tclsh at "$TCLSH_CMD"])
  with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
  if test x"${with_tcl}" != x; then
    AC_MSG_RESULT([$TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}])
  else
    AC_MSG_WARN([$TCLSH_CMD is unable to recommend a tclConfig.sh])
  fi
fi
if test x"${with_tcl}" != x; then
  if test -r ${with_tcl}/tclConfig.sh; then
    tclconfig="${with_tcl}/tclConfig.sh"
  else
    for i in tcl8.6 tcl9.0 lib; do
      if test -r ${with_tcl}/$i/tclConfig.sh; then
        tclconfig=${with_tcl}/$i/tclConfig.sh
        break
      fi
    done
  fi
  if test ! -r "${tclconfig}"; then
    AC_MSG_ERROR([no tclConfig.sh file found under ${with_tcl}])
  fi
else
  # If we have not yet found a tclConfig.sh file, look in $libdir whic is
  # set automatically by autoconf or by the --prefix command-line option.
  # See https://sqlite.org/forum/forumpost/e04e693439a22457
  libdir=${prefix}/lib
  if test -r ${libdir}/tclConfig.sh; then
    tclconfig=${libdir}/tclConfig.sh
  else
    for i in tcl8.6 tcl9.0 lib; do
      if test -r ${libdir}/$i/tclConfig.sh; then
        tclconfig=${libdir}/$i/tclConfig.sh
        break
      fi
    done
  fi
  if test ! -r "${tclconfig}"; then
    AC_MSG_ERROR([cannot find a usable tclConfig.sh file. 
      Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
      SQLite does not use TCL internally, but TCL is required to build SQLite
      from canonical sources and TCL is required for testing.])
  fi
fi
AC_MSG_RESULT([loading TCL configuration from ${tclconfig}])
. ${tclconfig}
AC_SUBST(TCL_INCLUDE_SPEC)
AC_SUBST(TCL_LIB_SPEC)
AC_SUBST(TCL_STUB_LIB_SPEC)
# There are lots of other configuration variables that are provided by the
# tclConfig.sh file and that could be included here.  But as of right now,
# TCL_LIB_SPEC is the only what that the Makefile uses.

if test x"$TCLSH_CMD" == x; then
  TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
  if test ! -x ${TCLSH_CMD}; then
    TCLSH_CMD_2=${TCL_EXEC_PREFIX}/bin/tclsh
    if test ! -x ${TCLSH_CMD_2}; then
      AC_MSG_WARN([cannot find a usable tclsh at either ${TCLSH_CMD} or ${TCLSH_CMD_2}])
      TCLSH_CMD=none
    else
      TCLSH_CMD=${TCLSH_CMD_2}
    fi
  fi
fi
if test "$TCLSH_CMD" = "none"; then
  # If we can't find a local tclsh, then building the amalgamation will fail.
  # We act as though --disable-amalgamation has been used.
  AC_MSG_WARN([Warning: can't find tclsh - defaulting to non-amalgamation build.])
  USE_AMALGAMATION=0
  TCLSH_CMD="tclsh"
  HAVE_TCL=0
else
  HAVE_TCL=1
fi
AC_SUBST(TCLSH_CMD)
AC_SUBST(HAVE_TCL)

AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])
if test "x${TCLLIBDIR+set}" != "xset" ; then

  for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
    if test -d $i ; then
      TCLLIBDIR=$i
      break
    fi
  done
  TCLLIBDIR="${TCLLIBDIR}/sqlite3"
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
fi

AC_SUBST(BUILD_EXEEXT)
AC_SUBST(SQLITE_OS_UNIX)
AC_SUBST(SQLITE_OS_WIN)
AC_SUBST(TARGET_EXEEXT)

##########
# Figure out all the parameters needed to compile against Tcl.
#
# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
# macros in the in the tcl.m4 file of the standard TCL distribution.
# Those macros could not be used directly since we have to make some
# minor changes to accomodate systems that do not have TCL installed.
#
AC_ARG_ENABLE(tcl, AS_HELP_STRING([--disable-tcl],[do not build TCL extension]),
      [use_tcl=$enableval],[use_tcl=yes])
if test "${use_tcl}" = "yes" ; then
  AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl=DIR],[directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval})
  AC_MSG_CHECKING([for Tcl configuration])
  AC_CACHE_VAL(ac_cv_c_tclconfig,[
    # First check to see if --with-tcl was specified.
    if test x"${with_tclconfig}" != x ; then
      if test -f "${with_tclconfig}/tclConfig.sh" ; then
        ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
      else
        AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
      fi
    fi

    # Start autosearch by asking tclsh
    if test x"${ac_cv_c_tclconfig}" = x ; then
      if test x"$cross_compiling" = xno; then
        for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}`
        do
          if test -f "$i/tclConfig.sh" ; then
            ac_cv_c_tclconfig="$i"
            break
          fi
        done
      fi
    fi

    # On ubuntu 14.10, $auto_path on tclsh is not quite correct.
    # So try again after applying corrections.
    if test x"${ac_cv_c_tclconfig}" = x ; then
      if test x"$cross_compiling" = xno; then
        for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'`
        do
          if test -f "$i/tclConfig.sh" ; then
            ac_cv_c_tclconfig="$i"
            break
          fi
        done
      fi
    fi

    # Recent versions of Xcode on Macs hid the tclConfig.sh file
    # in a strange place.
    if test x"${ac_cv_c_tclconfig}" = x ; then
      if test x"$cross_compiling" = xno; then
        for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib
        do
          if test -f "$i/tclConfig.sh" ; then
            ac_cv_c_tclconfig="$i"
            break
          fi
        done
      fi
    fi

    # then check for a private Tcl installation
    if test x"${ac_cv_c_tclconfig}" = x ; then
      for i in \
            ../tcl \
            `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
            `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \
            `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
            ../../tcl \
            `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
            `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
            `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
            ../../../tcl \
            `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
            `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
            `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null`
      do
        if test -f "$i/unix/tclConfig.sh" ; then
          ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
          break
        fi
      done
    fi

    # check in a few common install locations
    if test x"${ac_cv_c_tclconfig}" = x ; then
      for i in \
            `ls -d ${libdir} 2>/dev/null` \
            `ls -d /usr/local/lib 2>/dev/null` \
            `ls -d /usr/contrib/lib 2>/dev/null` \
            `ls -d /usr/lib 2>/dev/null`
      do
        if test -f "$i/tclConfig.sh" ; then
           ac_cv_c_tclconfig=`(cd $i; pwd)`
           break
        fi
      done
    fi

    # check in a few other private locations
    if test x"${ac_cv_c_tclconfig}" = x ; then
      for i in \
         ${srcdir}/../tcl \
         `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
         `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \
         `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null`
      do
        if test -f "$i/unix/tclConfig.sh" ; then
          ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
          break
        fi
      done
    fi
  ])

  if test x"${ac_cv_c_tclconfig}" = x ; then
    use_tcl=no
    AC_MSG_WARN(Can't find Tcl configuration definitions)
    AC_MSG_WARN(*** Without Tcl the regression tests cannot be executed ***)
    AC_MSG_WARN(*** Consider using --with-tcl=... to define location of Tcl ***)
  else
    TCL_BIN_DIR=${ac_cv_c_tclconfig}
    AC_MSG_RESULT(found $TCL_BIN_DIR/tclConfig.sh)

    AC_MSG_CHECKING([for existence of $TCL_BIN_DIR/tclConfig.sh])
    if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
      AC_MSG_RESULT([loading])
      . $TCL_BIN_DIR/tclConfig.sh
    else
      AC_MSG_RESULT([file not found])
    fi
    
    #
    # If the TCL_BIN_DIR is the build directory (not the install directory),
    # then set the common variable name to the value of the build variables.
    # For example, the variable TCL_LIB_SPEC will be set to the value
    # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
    # instead of TCL_BUILD_LIB_SPEC since it will work with both an
    # installed and uninstalled version of Tcl.
    #
    
    if test -f $TCL_BIN_DIR/Makefile ; then
      TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
      TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
      TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
    fi
    
    #
    # eval is required to do the TCL_DBGX substitution
    #
    
    eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
    eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
    eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
    
    eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
    eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
    eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
    
    AC_SUBST(TCL_VERSION)
    AC_SUBST(TCL_BIN_DIR)
    AC_SUBST(TCL_SRC_DIR)
    AC_SUBST(TCL_INCLUDE_SPEC)
    
    AC_SUBST(TCL_LIB_FILE)
    AC_SUBST(TCL_LIB_FLAG)
    AC_SUBST(TCL_LIB_SPEC)
    
    AC_SUBST(TCL_STUB_LIB_FILE)
    AC_SUBST(TCL_STUB_LIB_FLAG)
    AC_SUBST(TCL_STUB_LIB_SPEC)
    AC_SUBST(TCL_SHLIB_SUFFIX)
  fi
fi
if test "${use_tcl}" = "no" ; then
  HAVE_TCL=""
else
  HAVE_TCL=1
fi
AC_SUBST(HAVE_TCL)

##########
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
#
TARGET_READLINE_LIBS=""
TARGET_READLINE_INC=""
TARGET_HAVE_READLINE=0







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







409
410
411
412
413
414
415
























































































































































































416
417
418
419
420
421
422
fi

AC_SUBST(BUILD_EXEEXT)
AC_SUBST(SQLITE_OS_UNIX)
AC_SUBST(SQLITE_OS_WIN)
AC_SUBST(TARGET_EXEEXT)

























































































































































































##########
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
#
TARGET_READLINE_LIBS=""
TARGET_READLINE_INC=""
TARGET_HAVE_READLINE=0
Changes to ext/consio/console_io.c.
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#  endif
#  define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
# endif
#else
# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
#endif

#if CIO_WIN_WC_XLATE
/* Character used to represent a known-incomplete UTF-8 char group (�) */
static WCHAR cBadGroup = 0xfffd;
#endif

#if CIO_WIN_WC_XLATE
static HANDLE handleOfFile(FILE *pf){
  int fileDesc = _fileno(pf);
  union { intptr_t osfh; HANDLE fh; } fid = {
    (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
  };
  return fid.fh;







<
<
<
<
<







49
50
51
52
53
54
55





56
57
58
59
60
61
62
#  endif
#  define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
# endif
#else
# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
#endif






#if CIO_WIN_WC_XLATE
static HANDLE handleOfFile(FILE *pf){
  int fileDesc = _fileno(pf);
  union { intptr_t osfh; HANDLE fh; } fid = {
    (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
  };
  return fid.fh;
Changes to ext/expert/expert1.test.
461
462
463
464
465
466
467







468
469
470
471
472
473
474
  t1 t1_idx_00000062 {100 20}
  t1 t1_idx_000123a7 {100 50 17}
  t2 t2_idx_00000063 {100 20} 
  t2 t2_idx_00000064 {100 5} 
  t2 t2_idx_0001295b {100 20 5}
}








if 0 {
do_test expert1-6.0 {
  catchcmd :memory: {
.expert
select base64('');
.expert
select name from pragma_collation_list order by name collate uint;







>
>
>
>
>
>
>







461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  t1 t1_idx_00000062 {100 20}
  t1 t1_idx_000123a7 {100 50 17}
  t2 t2_idx_00000063 {100 20} 
  t2 t2_idx_00000064 {100 5} 
  t2 t2_idx_0001295b {100 20 5}
}

do_catchsql_test 5.4 {
  SELECT sqlite_expert_rem(123, 123);
} {1 {no such function: sqlite_expert_rem}}
do_catchsql_test 5.5 {
  SELECT sqlite_expert_sample();
} {1 {no such function: sqlite_expert_sample}}

if 0 {
do_test expert1-6.0 {
  catchcmd :memory: {
.expert
select base64('');
.expert
select name from pragma_collation_list order by name collate uint;
Changes to ext/expert/sqlite3expert.c.
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  (void)idxStr;
  (void)argc;
  (void)argv;
  rc = sqlite3_finalize(pCsr->pData);
  pCsr->pData = 0;
  if( rc==SQLITE_OK ){
    rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
        "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
    );
  }

  if( rc==SQLITE_OK ){
    rc = expertNext(cur);
  }
  return rc;







|







622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  (void)idxStr;
  (void)argc;
  (void)argv;
  rc = sqlite3_finalize(pCsr->pData);
  pCsr->pData = 0;
  if( rc==SQLITE_OK ){
    rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
        "SELECT * FROM main.%Q WHERE sqlite_expert_sample()", pVtab->pTab->zName
    );
  }

  if( rc==SQLITE_OK ){
    rc = expertNext(cur);
  }
  return rc;
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
    int nByte;                    /* Bytes of space allocated at z */
    int n;                        /* Size of buffer z */
    char *z;                      /* SQLITE_TEXT/BLOB value */
  } aSlot[1];
};

/*
** Implementation of scalar function rem().
*/
static void idxRemFunc(
  sqlite3_context *pCtx,
  int argc,
  sqlite3_value **argv
){
  struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx);
  struct IdxRemSlot *pSlot;
  int iSlot;
  assert( argc==2 );

  iSlot = sqlite3_value_int(argv[0]);
  assert( iSlot<=p->nSlot );
  pSlot = &p->aSlot[iSlot];

  switch( pSlot->eType ){
    case SQLITE_NULL:
      /* no-op */
      break;








|












|







1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
    int nByte;                    /* Bytes of space allocated at z */
    int n;                        /* Size of buffer z */
    char *z;                      /* SQLITE_TEXT/BLOB value */
  } aSlot[1];
};

/*
** Implementation of scalar function sqlite_expert_rem().
*/
static void idxRemFunc(
  sqlite3_context *pCtx,
  int argc,
  sqlite3_value **argv
){
  struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx);
  struct IdxRemSlot *pSlot;
  int iSlot;
  assert( argc==2 );

  iSlot = sqlite3_value_int(argv[0]);
  assert( iSlot<p->nSlot );
  pSlot = &p->aSlot[iSlot];

  switch( pSlot->eType ){
    case SQLITE_NULL:
      /* no-op */
      break;

1620
1621
1622
1623
1624
1625
1626

1627
1628
1629
1630
1631
1632
1633
1634
  /* Formulate the query text */
  sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
  while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
    const char *zComma = zCols==0 ? "" : ", ";
    const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
    const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
    zCols = idxAppendText(&rc, zCols, 

        "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
    );
    zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
  }
  sqlite3_reset(pIndexXInfo);
  if( rc==SQLITE_OK ){
    if( p->iSample==100 ){
      zQuery = sqlite3_mprintf(







>
|







1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
  /* Formulate the query text */
  sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
  while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
    const char *zComma = zCols==0 ? "" : ", ";
    const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
    const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
    zCols = idxAppendText(&rc, zCols, 
        "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s", 
        zComma, zName, nCol, zName, zColl
    );
    zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
  }
  sqlite3_reset(pIndexXInfo);
  if( rc==SQLITE_OK ){
    if( p->iSample==100 ){
      zQuery = sqlite3_mprintf(
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
  if( rc==SQLITE_OK ){
    int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
    pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte);
  }

  if( rc==SQLITE_OK ){
    sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
    rc = sqlite3_create_function(
        dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
    );
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(
        p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
    );
  }

  if( rc==SQLITE_OK ){
    pCtx->nSlot = nMax+1;
    rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex);
  }







|
|



|
|







1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
  if( rc==SQLITE_OK ){
    int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
    pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte);
  }

  if( rc==SQLITE_OK ){
    sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
    rc = sqlite3_create_function(dbrem, "sqlite_expert_rem", 
        2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
    );
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(p->db, "sqlite_expert_sample", 
        0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
    );
  }

  if( rc==SQLITE_OK ){
    pCtx->nSlot = nMax+1;
    rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex);
  }
1811
1812
1813
1814
1815
1816
1817



1818
1819
1820
1821
1822
1823
1824
    sqlite3_free(pCtx);
  }

  if( rc==SQLITE_OK ){
    rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
  }




  sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
  return rc;
}

/*
** Define and possibly pretend to use a useless collation sequence.
** This pretense allows expert to accept SQL using custom collations.







>
>
>







1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
    sqlite3_free(pCtx);
  }

  if( rc==SQLITE_OK ){
    rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
  }

  sqlite3_create_function(p->db, "sqlite_expert_rem", 2, SQLITE_UTF8, 0,0,0,0);
  sqlite3_create_function(p->db, "sqlite_expert_sample", 0,SQLITE_UTF8,0,0,0,0);

  sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
  return rc;
}

/*
** Define and possibly pretend to use a useless collation sequence.
** This pretense allows expert to accept SQL using custom collations.
Changes to ext/expert/test_expert.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
*/

#if defined(SQLITE_TEST)

#include "sqlite3expert.h"
#include <assert.h>
#include <string.h>

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

#ifndef SQLITE_OMIT_VIRTUALTABLE

/*
** 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.







<
<
<
<
|
<
<
<
<







12
13
14
15
16
17
18




19




20
21
22
23
24
25
26
*/

#if defined(SQLITE_TEST)

#include "sqlite3expert.h"
#include <assert.h>
#include <string.h>




#include "tclsqlite.h"





#ifndef SQLITE_OMIT_VIRTUALTABLE

/*
** 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.
Changes to ext/fts3/fts3_snippet.c.
394
395
396
397
398
399
400

401
402
403
404
405
406
407
        iEnd = pPhrase->iHead;
      }
    }
    if( iEnd==0x7FFFFFFF ){
      return 1;
    }


    pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
    for(i=0; i<pIter->nPhrase; i++){
      SnippetPhrase *pPhrase = &pIter->aPhrase[i];
      fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1);
      fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart);
    }
  }







>







394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
        iEnd = pPhrase->iHead;
      }
    }
    if( iEnd==0x7FFFFFFF ){
      return 1;
    }

    assert( pIter->nSnippet>=0 );
    pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
    for(i=0; i<pIter->nPhrase; i++){
      SnippetPhrase *pPhrase = &pIter->aPhrase[i];
      fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1);
      fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart);
    }
  }
Changes to ext/fts3/fts3_test.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
** testing. It contains a Tcl command that can be used to test if a document
** matches an FTS NEAR expression.
**
** As of March 2012, it also contains a version 1 tokenizer used for testing
** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly.
*/

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif
#include <string.h>
#include <assert.h>

#if defined(SQLITE_TEST)
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)

/* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */







<
<
<
|
<
<
<
<







14
15
16
17
18
19
20



21




22
23
24
25
26
27
28
** testing. It contains a Tcl command that can be used to test if a document
** matches an FTS NEAR expression.
**
** As of March 2012, it also contains a version 1 tokenizer used for testing
** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly.
*/




#include "tclsqlite.h"




#include <string.h>
#include <assert.h>

#if defined(SQLITE_TEST)
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)

/* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */
163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
  NearPhrase *aPhrase = 0;
  NearDocument doc = {0, 0};
  Tcl_Obj **apDocToken;
  Tcl_Obj *pRet;
  Tcl_Obj *pPhrasecount = 0;
  
  Tcl_Obj **apExprToken;
  int nExprToken;


  UNUSED_PARAMETER(clientData);

  /* Must have 3 or more arguments. */
  if( objc<3 || (objc%2)==0 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DOCUMENT EXPR ?OPTION VALUE?...");
    rc = TCL_ERROR;







|
>







156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  NearPhrase *aPhrase = 0;
  NearDocument doc = {0, 0};
  Tcl_Obj **apDocToken;
  Tcl_Obj *pRet;
  Tcl_Obj *pPhrasecount = 0;
  
  Tcl_Obj **apExprToken;
  Tcl_Size nExprToken;
  Tcl_Size nn;

  UNUSED_PARAMETER(clientData);

  /* Must have 3 or more arguments. */
  if( objc<3 || (objc%2)==0 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DOCUMENT EXPR ?OPTION VALUE?...");
    rc = TCL_ERROR;
197
198
199
200
201
202
203
204

205
206
207
208

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

233
234
235
236
237
238
239
240
241
    switch( aOpt[iOpt].eOpt ){
      case NM_PHRASECOUNTS:
        pPhrasecount = objv[ii+1];
        break;
    }
  }

  rc = Tcl_ListObjGetElements(interp, objv[1], &doc.nToken, &apDocToken);

  if( rc!=TCL_OK ) goto near_match_out;
  doc.aToken = (NearToken *)ckalloc(doc.nToken*sizeof(NearToken));
  for(ii=0; ii<doc.nToken; ii++){
    doc.aToken[ii].z = Tcl_GetStringFromObj(apDocToken[ii], &doc.aToken[ii].n);

  }

  rc = Tcl_ListObjGetElements(interp, objv[2], &nExprToken, &apExprToken);
  if( rc!=TCL_OK ) goto near_match_out;

  nPhrase = (nExprToken + 1) / 2;
  aPhrase = (NearPhrase *)ckalloc(nPhrase * sizeof(NearPhrase));
  memset(aPhrase, 0, nPhrase * sizeof(NearPhrase));
  for(ii=0; ii<nPhrase; ii++){
    Tcl_Obj *pPhrase = apExprToken[ii*2];
    Tcl_Obj **apToken;
    int nToken;
    int jj;

    rc = Tcl_ListObjGetElements(interp, pPhrase, &nToken, &apToken);
    if( rc!=TCL_OK ) goto near_match_out;
    if( nToken>NM_MAX_TOKEN ){
      Tcl_AppendResult(interp, "Too many tokens in phrase", 0);
      rc = TCL_ERROR;
      goto near_match_out;
    }
    for(jj=0; jj<nToken; jj++){
      NearToken *pT = &aPhrase[ii].aToken[jj];
      pT->z = Tcl_GetStringFromObj(apToken[jj], &pT->n);

    }
    aPhrase[ii].nToken = nToken;
  }
  for(ii=1; ii<nPhrase; ii++){
    Tcl_Obj *pNear = apExprToken[2*ii-1];
    int nNear;
    rc = Tcl_GetIntFromObj(interp, pNear, &nNear);
    if( rc!=TCL_OK ) goto near_match_out;
    aPhrase[ii].nNear = nNear;







|
>



|
>





|





|









|

|
>

|







191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
    switch( aOpt[iOpt].eOpt ){
      case NM_PHRASECOUNTS:
        pPhrasecount = objv[ii+1];
        break;
    }
  }

  rc = Tcl_ListObjGetElements(interp, objv[1], &nn, &apDocToken);
  doc.nToken = (int)nn;
  if( rc!=TCL_OK ) goto near_match_out;
  doc.aToken = (NearToken *)ckalloc(doc.nToken*sizeof(NearToken));
  for(ii=0; ii<doc.nToken; ii++){
    doc.aToken[ii].z = Tcl_GetStringFromObj(apDocToken[ii], &nn);
    doc.aToken[ii].n = (int)nn;
  }

  rc = Tcl_ListObjGetElements(interp, objv[2], &nExprToken, &apExprToken);
  if( rc!=TCL_OK ) goto near_match_out;

  nPhrase = (int)(nExprToken + 1) / 2;
  aPhrase = (NearPhrase *)ckalloc(nPhrase * sizeof(NearPhrase));
  memset(aPhrase, 0, nPhrase * sizeof(NearPhrase));
  for(ii=0; ii<nPhrase; ii++){
    Tcl_Obj *pPhrase = apExprToken[ii*2];
    Tcl_Obj **apToken;
    Tcl_Size nToken;
    int jj;

    rc = Tcl_ListObjGetElements(interp, pPhrase, &nToken, &apToken);
    if( rc!=TCL_OK ) goto near_match_out;
    if( nToken>NM_MAX_TOKEN ){
      Tcl_AppendResult(interp, "Too many tokens in phrase", 0);
      rc = TCL_ERROR;
      goto near_match_out;
    }
    for(jj=0; jj<(int)nToken; jj++){
      NearToken *pT = &aPhrase[ii].aToken[jj];
      pT->z = Tcl_GetStringFromObj(apToken[jj], &nn);
      pT->n = (int)nn;
    }
    aPhrase[ii].nToken = (int)nToken;
  }
  for(ii=1; ii<nPhrase; ii++){
    Tcl_Obj *pNear = apExprToken[2*ii-1];
    int nNear;
    rc = Tcl_GetIntFromObj(interp, pNear, &nNear);
    if( rc!=TCL_OK ) goto near_match_out;
    aPhrase[ii].nNear = nNear;
Changes to ext/fts3/fts3_tokenizer.c.
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  sqlite3_free(zCopy);
  return rc;
}


#ifdef SQLITE_TEST

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <string.h>

/*
** Implementation of a special SQL scalar function for testing tokenizers 
** designed to be used in concert with the Tcl testing framework. This
** function must be called with two or more arguments:
**







<
<
<
|
<







222
223
224
225
226
227
228



229

230
231
232
233
234
235
236
  sqlite3_free(zCopy);
  return rc;
}


#ifdef SQLITE_TEST




#include "tclsqlite.h"

#include <string.h>

/*
** Implementation of a special SQL scalar function for testing tokenizers 
** designed to be used in concert with the Tcl testing framework. This
** function must be called with two or more arguments:
**
Changes to ext/fts5/fts5_expr.c.
2259
2260
2261
2262
2263
2264
2265



2266
2267
2268
2269
2270
2271
2272
    default: assert( pNode->eType==FTS5_NOT ); {
      pNode->xNext = fts5ExprNodeNext_NOT;
      break;
    };
  }
}




static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
  int ii = p->nChild;
  if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
    int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
    memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
    p->nChild += pSub->nChild;
    sqlite3_free(pSub);







>
>
>







2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
    default: assert( pNode->eType==FTS5_NOT ); {
      pNode->xNext = fts5ExprNodeNext_NOT;
      break;
    };
  }
}

/*
** Add pSub as a child of p.
*/
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
  int ii = p->nChild;
  if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
    int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
    memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
    p->nChild += pSub->nChild;
    sqlite3_free(pSub);
2403
2404
2405
2406
2407
2408
2409
2410
2411


2412
2413
2414

2415
2416

2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
                || pPhrase->nTerm>1
                || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
              ){
              sqlite3Fts5ParseError(pParse, 
                  "fts5: %s queries are not supported (detail!=full)", 
                  pNear->nPhrase==1 ? "phrase": "NEAR"
              );
              sqlite3_free(pRet);
              pRet = 0;


            }
          }
        }else{

          fts5ExprAddChildren(pRet, pLeft);
          fts5ExprAddChildren(pRet, pRight);

          if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
            sqlite3Fts5ParseError(pParse, 
                "fts5 expression tree is too large (maximum depth %d)", 
                SQLITE_FTS5_MAX_EXPR_DEPTH
            );
            sqlite3_free(pRet);
            pRet = 0;
          }
        }
      }
    }
  }








|

>
>



>


>





|







2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
                || pPhrase->nTerm>1
                || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
              ){
              sqlite3Fts5ParseError(pParse, 
                  "fts5: %s queries are not supported (detail!=full)", 
                  pNear->nPhrase==1 ? "phrase": "NEAR"
              );
              sqlite3Fts5ParseNodeFree(pRet);
              pRet = 0;
              pNear = 0;
              assert( pLeft==0 && pRight==0 );
            }
          }
        }else{
          assert( pNear==0 );
          fts5ExprAddChildren(pRet, pLeft);
          fts5ExprAddChildren(pRet, pRight);
          pLeft = pRight = 0;
          if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
            sqlite3Fts5ParseError(pParse, 
                "fts5 expression tree is too large (maximum depth %d)", 
                SQLITE_FTS5_MAX_EXPR_DEPTH
            );
            sqlite3Fts5ParseNodeFree(pRet);
            pRet = 0;
          }
        }
      }
    }
  }

2453
2454
2455
2456
2457
2458
2459

2460
2461
2462
2463
2464
2465
2466
        || pLeft->eType==FTS5_TERM
        || pLeft->eType==FTS5_EOF
        || pLeft->eType==FTS5_AND
    );
    assert( pRight->eType==FTS5_STRING 
        || pRight->eType==FTS5_TERM 
        || pRight->eType==FTS5_EOF 

    );

    if( pLeft->eType==FTS5_AND ){
      pPrev = pLeft->apChild[pLeft->nChild-1];
    }else{
      pPrev = pLeft;
    }







>







2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
        || pLeft->eType==FTS5_TERM
        || pLeft->eType==FTS5_EOF
        || pLeft->eType==FTS5_AND
    );
    assert( pRight->eType==FTS5_STRING 
        || pRight->eType==FTS5_TERM 
        || pRight->eType==FTS5_EOF 
        || (pRight->eType==FTS5_AND && pParse->bPhraseToAnd) 
    );

    if( pLeft->eType==FTS5_AND ){
      pPrev = pLeft->apChild[pLeft->nChild-1];
    }else{
      pPrev = pLeft;
    }
Changes to ext/fts5/fts5_main.c.
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505




2506
2507
2508
2509
2510
2511
2512
2513
2514
    }
  }

  return pRet;
}

static void fts5ApiPhraseNext(
  Fts5Context *pUnused, 
  Fts5PhraseIter *pIter, 
  int *piCol, int *piOff
){
  UNUSED_PARAM(pUnused);
  if( pIter->a>=pIter->b ){
    *piCol = -1;
    *piOff = -1;
  }else{
    int iVal;
    pIter->a += fts5GetVarint32(pIter->a, iVal);
    if( iVal==1 ){




      pIter->a += fts5GetVarint32(pIter->a, iVal);
      *piCol = iVal;
      *piOff = 0;
      pIter->a += fts5GetVarint32(pIter->a, iVal);
    }
    *piOff += (iVal-2);
  }
}








|



<







>
>
>
>

|







2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497

2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
    }
  }

  return pRet;
}

static void fts5ApiPhraseNext(
  Fts5Context *pCtx, 
  Fts5PhraseIter *pIter, 
  int *piCol, int *piOff
){

  if( pIter->a>=pIter->b ){
    *piCol = -1;
    *piOff = -1;
  }else{
    int iVal;
    pIter->a += fts5GetVarint32(pIter->a, iVal);
    if( iVal==1 ){
      /* Avoid returning a (*piCol) value that is too large for the table,
      ** even if the position-list is corrupt. The caller might not be
      ** expecting it.  */
      int nCol = ((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab))->pConfig->nCol;
      pIter->a += fts5GetVarint32(pIter->a, iVal);
      *piCol = (iVal>=nCol ? nCol-1 : iVal);
      *piOff = 0;
      pIter->a += fts5GetVarint32(pIter->a, iVal);
    }
    *piOff += (iVal-2);
  }
}

Changes to ext/fts5/fts5_tcl.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
**
******************************************************************************
**
*/


#ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

#ifdef SQLITE_ENABLE_FTS5

#include "fts5.h"
#include <string.h>
#include <assert.h>








<
<
<
|
<
<
<
<







10
11
12
13
14
15
16



17




18
19
20
21
22
23
24
**
******************************************************************************
**
*/


#ifdef SQLITE_TEST



#include "tclsqlite.h"





#ifdef SQLITE_ENABLE_FTS5

#include "fts5.h"
#include <string.h>
#include <assert.h>

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
      rc = p->pApi->xColumnTotalSize(p->pFts, iCol, &nSize);
      if( rc==SQLITE_OK ){
        Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize));
      }
      break;
    }
    CASE(3, "xTokenize") {
      int nText;
      char *zText = Tcl_GetStringFromObj(objv[2], &nText);
      F5tFunction ctx;
      ctx.interp = interp;
      ctx.pScript = objv[3];
      rc = p->pApi->xTokenize(p->pFts, zText, nText, &ctx, xTokenizeCb);
      if( rc==SQLITE_OK ){
        Tcl_ResetResult(interp);
      }
      return rc;
    }
    CASE(4, "xPhraseCount") {
      int nPhrase;







|




|







287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
      rc = p->pApi->xColumnTotalSize(p->pFts, iCol, &nSize);
      if( rc==SQLITE_OK ){
        Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize));
      }
      break;
    }
    CASE(3, "xTokenize") {
      Tcl_Size nText;
      char *zText = Tcl_GetStringFromObj(objv[2], &nText);
      F5tFunction ctx;
      ctx.interp = interp;
      ctx.pScript = objv[3];
      rc = p->pApi->xTokenize(p->pFts, zText, (int)nText, &ctx, xTokenizeCb);
      if( rc==SQLITE_OK ){
        Tcl_ResetResult(interp);
      }
      return rc;
    }
    CASE(4, "xPhraseCount") {
      int nPhrase;
616
617
618
619
620
621
622
623
624
625
626
627
628

629
630
631

632
633
634
635
636
637
638
639
640
641
642
643

644
645
646
647
648
649
650
651
652
  Tcl_DecrRefCount(pEval);
  Tcl_DeleteCommand(p->interp, zCmd);

  if( rc!=TCL_OK ){
    sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1);
  }else{
    Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
    int n;
    const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
    char c = zType[0];
    if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
      /* Only return a BLOB type if the Tcl variable is a bytearray and
      ** has no string representation. */

      unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &n);
      sqlite3_result_blob(pCtx, data, n, SQLITE_TRANSIENT);
    }else if( c=='b' && strcmp(zType,"boolean")==0 ){

      Tcl_GetIntFromObj(0, pVar, &n);
      sqlite3_result_int(pCtx, n);
    }else if( c=='d' && strcmp(zType,"double")==0 ){
      double r;
      Tcl_GetDoubleFromObj(0, pVar, &r);
      sqlite3_result_double(pCtx, r);
    }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
          (c=='i' && strcmp(zType,"int")==0) ){
      Tcl_WideInt v;
      Tcl_GetWideIntFromObj(0, pVar, &v);
      sqlite3_result_int64(pCtx, v);
    }else{

      unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
      sqlite3_result_text(pCtx, (char *)data, n, SQLITE_TRANSIENT);
    }
  }
}

static void xF5tDestroy(void *pCtx){
  F5tFunction *p = (F5tFunction*)pCtx;
  Tcl_DecrRefCount(p->pScript);







<





>
|
|

>












>
|
|







609
610
611
612
613
614
615

616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  Tcl_DecrRefCount(pEval);
  Tcl_DeleteCommand(p->interp, zCmd);

  if( rc!=TCL_OK ){
    sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1);
  }else{
    Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);

    const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
    char c = zType[0];
    if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
      /* Only return a BLOB type if the Tcl variable is a bytearray and
      ** has no string representation. */
      Tcl_Size nn;
      unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &nn);
      sqlite3_result_blob(pCtx, data, (int)nn, SQLITE_TRANSIENT);
    }else if( c=='b' && strcmp(zType,"boolean")==0 ){
      int n;
      Tcl_GetIntFromObj(0, pVar, &n);
      sqlite3_result_int(pCtx, n);
    }else if( c=='d' && strcmp(zType,"double")==0 ){
      double r;
      Tcl_GetDoubleFromObj(0, pVar, &r);
      sqlite3_result_double(pCtx, r);
    }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
          (c=='i' && strcmp(zType,"int")==0) ){
      Tcl_WideInt v;
      Tcl_GetWideIntFromObj(0, pVar, &v);
      sqlite3_result_int64(pCtx, v);
    }else{
      Tcl_Size nn;
      unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &nn);
      sqlite3_result_text(pCtx, (char*)data, (int)nn, SQLITE_TRANSIENT);
    }
  }
}

static void xF5tDestroy(void *pCtx){
  F5tFunction *p = (F5tFunction*)pCtx;
  Tcl_DecrRefCount(p->pScript);
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
static int SQLITE_TCLAPI f5tTokenize(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  char *zText;
  int nText;
  sqlite3 *db = 0;
  fts5_api *pApi = 0;
  Fts5Tokenizer *pTok = 0;
  fts5_tokenizer tokenizer;
  Tcl_Obj *pRet = 0;
  void *pUserdata;
  int rc;

  int nArg;
  const char **azArg;
  F5tTokenizeCtx ctx;

  if( objc!=4 && objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "?-subst? DB NAME TEXT");
    return TCL_ERROR;
  }







|








|







726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
static int SQLITE_TCLAPI f5tTokenize(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  char *zText;
  Tcl_Size nText;
  sqlite3 *db = 0;
  fts5_api *pApi = 0;
  Fts5Tokenizer *pTok = 0;
  fts5_tokenizer tokenizer;
  Tcl_Obj *pRet = 0;
  void *pUserdata;
  int rc;

  Tcl_Size nArg;
  const char **azArg;
  F5tTokenizeCtx ctx;

  if( objc!=4 && objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "?-subst? DB NAME TEXT");
    return TCL_ERROR;
  }
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798

  rc = pApi->xFindTokenizer(pApi, azArg[0], &pUserdata, &tokenizer);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], 0);
    return TCL_ERROR;
  }

  rc = tokenizer.xCreate(pUserdata, &azArg[1], nArg-1, &pTok);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0);
    return TCL_ERROR;
  }

  pRet = Tcl_NewObj();
  Tcl_IncrRefCount(pRet);
  ctx.bSubst = (objc==5);
  ctx.pRet = pRet;
  ctx.zInput = zText;
  rc = tokenizer.xTokenize(
      pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText, nText, xTokenizeCb2
  );
  tokenizer.xDelete(pTok);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", 0);
    Tcl_DecrRefCount(pRet);
    return TCL_ERROR;
  }







|











|







767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793

  rc = pApi->xFindTokenizer(pApi, azArg[0], &pUserdata, &tokenizer);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], 0);
    return TCL_ERROR;
  }

  rc = tokenizer.xCreate(pUserdata, &azArg[1], (int)(nArg-1), &pTok);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0);
    return TCL_ERROR;
  }

  pRet = Tcl_NewObj();
  Tcl_IncrRefCount(pRet);
  ctx.bSubst = (objc==5);
  ctx.pRet = pRet;
  ctx.zInput = zText;
  rc = tokenizer.xTokenize(
      pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText,(int)nText, xTokenizeCb2
  );
  tokenizer.xDelete(pTok);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", 0);
    Tcl_DecrRefCount(pRet);
    return TCL_ERROR;
  }
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  F5tTokenizerContext *p = (F5tTokenizerContext*)clientData;
  int iStart;
  int iEnd;
  int nToken;
  int tflags = 0;
  char *zToken;
  int rc;

  if( objc==5 ){
    int nArg;
    char *zArg = Tcl_GetStringFromObj(objv[1], &nArg);
    if( nArg<=10 && nArg>=2 && memcmp("-colocated", zArg, nArg)==0 ){
      tflags |= FTS5_TOKEN_COLOCATED;
    }else{
      goto usage;
    }
  }else if( objc!=4 ){







|





|







1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  F5tTokenizerContext *p = (F5tTokenizerContext*)clientData;
  int iStart;
  int iEnd;
  Tcl_Size nToken;
  int tflags = 0;
  char *zToken;
  int rc;

  if( objc==5 ){
    Tcl_Size nArg;
    char *zArg = Tcl_GetStringFromObj(objv[1], &nArg);
    if( nArg<=10 && nArg>=2 && memcmp("-colocated", zArg, nArg)==0 ){
      tflags |= FTS5_TOKEN_COLOCATED;
    }else{
      goto usage;
    }
  }else if( objc!=4 ){
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
  if( p->xToken==0 ){
    Tcl_AppendResult(interp, 
        "sqlite3_fts5_token may only be used by tokenizer callback", 0
    );
    return TCL_ERROR;
  }

  rc = p->xToken(p->pCtx, tflags, zToken, nToken, iStart, iEnd);
  Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
  return rc==SQLITE_OK ? TCL_OK : TCL_ERROR;

 usage:
  Tcl_WrongNumArgs(interp, 1, objv, "?-colocated? TEXT START END");
  return TCL_ERROR;
}







|







1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
  if( p->xToken==0 ){
    Tcl_AppendResult(interp, 
        "sqlite3_fts5_token may only be used by tokenizer callback", 0
    );
    return TCL_ERROR;
  }

  rc = p->xToken(p->pCtx, tflags, zToken, (int)nToken, iStart, iEnd);
  Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
  return rc==SQLITE_OK ? TCL_OK : TCL_ERROR;

 usage:
  Tcl_WrongNumArgs(interp, 1, objv, "?-colocated? TEXT START END");
  return TCL_ERROR;
}
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
static int SQLITE_TCLAPI f5tTokenHash(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  char *z;
  int n;
  unsigned int iVal;
  int nSlot;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "NSLOT TOKEN");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &nSlot) ){
    return TCL_ERROR;
  }
  z = Tcl_GetStringFromObj(objv[2], &n);

  iVal = f5t_fts5HashKey(nSlot, z, n);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
  return TCL_OK;
}

static int SQLITE_TCLAPI f5tRegisterMatchinfo(
  void * clientData,
  Tcl_Interp *interp,







|












|







1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
static int SQLITE_TCLAPI f5tTokenHash(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  char *z;
  Tcl_Size n;
  unsigned int iVal;
  int nSlot;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "NSLOT TOKEN");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &nSlot) ){
    return TCL_ERROR;
  }
  z = Tcl_GetStringFromObj(objv[2], &n);

  iVal = f5t_fts5HashKey(nSlot, z, (int)n);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
  return TCL_OK;
}

static int SQLITE_TCLAPI f5tRegisterMatchinfo(
  void * clientData,
  Tcl_Interp *interp,
Changes to ext/fts5/fts5_tokenize.c.
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

93
94
95
96
97
98
99
    p = sqlite3_malloc(sizeof(AsciiTokenizer));
    if( p==0 ){
      rc = SQLITE_NOMEM;
    }else{
      int i;
      memset(p, 0, sizeof(AsciiTokenizer));
      memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
      for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
        const char *zArg = azArg[i+1];
        if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
          fts5AsciiAddExceptions(p, zArg, 1);
        }else
        if( 0==sqlite3_stricmp(azArg[i], "separators") ){
          fts5AsciiAddExceptions(p, zArg, 0);
        }else{
          rc = SQLITE_ERROR;
        }
      }

      if( rc!=SQLITE_OK ){
        fts5AsciiDelete((Fts5Tokenizer*)p);
        p = 0;
      }
    }
  }








|










>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
    p = sqlite3_malloc(sizeof(AsciiTokenizer));
    if( p==0 ){
      rc = SQLITE_NOMEM;
    }else{
      int i;
      memset(p, 0, sizeof(AsciiTokenizer));
      memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
      for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
        const char *zArg = azArg[i+1];
        if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
          fts5AsciiAddExceptions(p, zArg, 1);
        }else
        if( 0==sqlite3_stricmp(azArg[i], "separators") ){
          fts5AsciiAddExceptions(p, zArg, 0);
        }else{
          rc = SQLITE_ERROR;
        }
      }
      if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR;
      if( rc!=SQLITE_OK ){
        fts5AsciiDelete((Fts5Tokenizer*)p);
        p = 0;
      }
    }
  }

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
      p->nFold = 64;
      p->aFold = sqlite3_malloc64(p->nFold * sizeof(char));
      if( p->aFold==0 ){
        rc = SQLITE_NOMEM;
      }

      /* Search for a "categories" argument */
      for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
        if( 0==sqlite3_stricmp(azArg[i], "categories") ){
          zCat = azArg[i+1];
        }
      }

      if( rc==SQLITE_OK ){
        rc = unicodeSetCategories(p, zCat);
      }

      for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
        const char *zArg = azArg[i+1];
        if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
          if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
            rc = SQLITE_ERROR;
          }else{
            p->eRemoveDiacritic = (zArg[0] - '0');
            assert( p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_NONE







|




<




|







378
379
380
381
382
383
384
385
386
387
388
389

390
391
392
393
394
395
396
397
398
399
400
401
      p->nFold = 64;
      p->aFold = sqlite3_malloc64(p->nFold * sizeof(char));
      if( p->aFold==0 ){
        rc = SQLITE_NOMEM;
      }

      /* Search for a "categories" argument */
      for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
        if( 0==sqlite3_stricmp(azArg[i], "categories") ){
          zCat = azArg[i+1];
        }
      }

      if( rc==SQLITE_OK ){
        rc = unicodeSetCategories(p, zCat);
      }

      for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
        const char *zArg = azArg[i+1];
        if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
          if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
            rc = SQLITE_ERROR;
          }else{
            p->eRemoveDiacritic = (zArg[0] - '0');
            assert( p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_NONE
412
413
414
415
416
417
418

419
420
421
422
423
424
425
        }else
        if( 0==sqlite3_stricmp(azArg[i], "categories") ){
          /* no-op */
        }else{
          rc = SQLITE_ERROR;
        }
      }


    }else{
      rc = SQLITE_NOMEM;
    }
    if( rc!=SQLITE_OK ){
      fts5UnicodeDelete((Fts5Tokenizer*)p);
      p = 0;







>







412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
        }else
        if( 0==sqlite3_stricmp(azArg[i], "categories") ){
          /* no-op */
        }else{
          rc = SQLITE_ERROR;
        }
      }
      if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;

    }else{
      rc = SQLITE_NOMEM;
    }
    if( rc!=SQLITE_OK ){
      fts5UnicodeDelete((Fts5Tokenizer*)p);
      p = 0;
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318

1319
1320
1321
1322
1323
1324
1325
  UNUSED_PARAM(pUnused);
  if( pNew==0 ){
    rc = SQLITE_NOMEM;
  }else{
    int i;
    pNew->bFold = 1;
    pNew->iFoldParam = 0;
    for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
      const char *zArg = azArg[i+1];
      if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
        if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
          rc = SQLITE_ERROR;
        }else{
          pNew->bFold = (zArg[0]=='0');
        }
      }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
        if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
          rc = SQLITE_ERROR;
        }else{
          pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
        }
      }else{
        rc = SQLITE_ERROR;
      }
    }


    if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
      rc = SQLITE_ERROR;
    }

    if( rc!=SQLITE_OK ){
      fts5TriDelete((Fts5Tokenizer*)pNew);







|

















>







1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
  UNUSED_PARAM(pUnused);
  if( pNew==0 ){
    rc = SQLITE_NOMEM;
  }else{
    int i;
    pNew->bFold = 1;
    pNew->iFoldParam = 0;
    for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
      const char *zArg = azArg[i+1];
      if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
        if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
          rc = SQLITE_ERROR;
        }else{
          pNew->bFold = (zArg[0]=='0');
        }
      }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
        if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
          rc = SQLITE_ERROR;
        }else{
          pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
        }
      }else{
        rc = SQLITE_ERROR;
      }
    }
    if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;

    if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
      rc = SQLITE_ERROR;
    }

    if( rc!=SQLITE_OK ){
      fts5TriDelete((Fts5Tokenizer*)pNew);
Changes to ext/fts5/test/fts5aa.test.
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  CREATE VIRTUAL TABLE n1 USING fts5(a);
  INSERT INTO n1 VALUES('a b c d');
}

proc funk {} {
  db eval { UPDATE n1_config SET v=50 WHERE k='version' }
  set fd [db incrblob main n1_data block 10]
  fconfigure $fd -encoding binary -translation binary
#  puts -nonewline $fd "\x44\x45"
  close $fd
}
db func funk funk

# This test case corrupts the structure record within the first invocation
# of function funk(). Which used to cause the bm25() function to throw an
# exception. But since bm25() can now used the cached structure record,
# it never sees the corruption introduced by funk() and so the following 
# statement no longer fails.
#
do_catchsql_test 16.2 {
  SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
} {0 {{} -1e-06 {}}}
# {1 {SQL logic error}}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db







|












|







436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  CREATE VIRTUAL TABLE n1 USING fts5(a);
  INSERT INTO n1 VALUES('a b c d');
}

proc funk {} {
  db eval { UPDATE n1_config SET v=50 WHERE k='version' }
  set fd [db incrblob main n1_data block 10]
  fconfigure $fd -translation binary
#  puts -nonewline $fd "\x44\x45"
  close $fd
}
db func funk funk

# This test case corrupts the structure record within the first invocation
# of function funk(). Which used to cause the bm25() function to throw an
# exception. But since bm25() can now used the cached structure record,
# it never sees the corruption introduced by funk() and so the following 
# statement no longer fails.
#
do_catchsql_test 16.2 {
  SELECT funk(), format('%g',bm25(n1)), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
} {0 {{} -1e-06 {}}}
# {1 {SQL logic error}}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
Changes to ext/fts5/test/fts5corrupt2.test.
96
97
98
99
100
101
102

103
104
105
106
107
108
109
# corruption. It may not report the db as corrupt because truncating the
# final leaf to some sizes may create a valid leaf page.
#
set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}] 
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}]
sqlite3_db_config db DEFENSIVE 0

for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
  do_execsql_test 2.$i.1 {
    BEGIN;
      UPDATE t1_data SET block = substr(block, 1, $i) WHERE rowid=$lrowid;
  }

  do_catchsql_test 2.$i.2 {







>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# corruption. It may not report the db as corrupt because truncating the
# final leaf to some sizes may create a valid leaf page.
#
set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}] 
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}]
sqlite3_db_config db DEFENSIVE 0
unset -nocomplain res
for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
  do_execsql_test 2.$i.1 {
    BEGIN;
      UPDATE t1_data SET block = substr(block, 1, $i) WHERE rowid=$lrowid;
  }

  do_catchsql_test 2.$i.2 {
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  foreach rowid [db eval {SELECT rowid FROM x3_data WHERE rowid>10}] {
    if {$rowid & $mask} continue
    incr tn2
    do_test 3.$tn.$tn2.1 {
      execsql BEGIN

      set fd [db incrblob main x3_data block $rowid]
      fconfigure $fd -encoding binary -translation binary
      set existing [read $fd [string length $hdr]]
      seek $fd 0
      puts -nonewline $fd $hdr
      close $fd

      set res [catchsql {SELECT rowid FROM x3 WHERE x3 MATCH 'x AND a'}]
      if {$res == "1 {database disk image is malformed}"} {incr nCorrupt}







|







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  foreach rowid [db eval {SELECT rowid FROM x3_data WHERE rowid>10}] {
    if {$rowid & $mask} continue
    incr tn2
    do_test 3.$tn.$tn2.1 {
      execsql BEGIN

      set fd [db incrblob main x3_data block $rowid]
      fconfigure $fd -translation binary
      set existing [read $fd [string length $hdr]]
      seek $fd 0
      puts -nonewline $fd $hdr
      close $fd

      set res [catchsql {SELECT rowid FROM x3 WHERE x3 MATCH 'x AND a'}]
      if {$res == "1 {database disk image is malformed}"} {incr nCorrupt}
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  foreach rowid [db eval {SELECT rowid FROM x5_data WHERE rowid>10}] {
    if {$rowid & $mask} continue
    incr tn2
    do_test 5.$tn.$tn2 {
      execsql BEGIN

      set fd [db incrblob main x5_data block $rowid]
      fconfigure $fd -encoding binary -translation binary
      puts -nonewline $fd $hdr
      close $fd

      catchsql { INSERT INTO x5(x5) VALUES('integrity-check') }
      set {} {}
    } {}








|







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  foreach rowid [db eval {SELECT rowid FROM x5_data WHERE rowid>10}] {
    if {$rowid & $mask} continue
    incr tn2
    do_test 5.$tn.$tn2 {
      execsql BEGIN

      set fd [db incrblob main x5_data block $rowid]
      fconfigure $fd -translation binary
      puts -nonewline $fd $hdr
      close $fd

      catchsql { INSERT INTO x5(x5) VALUES('integrity-check') }
      set {} {}
    } {}

Changes to ext/fts5/test/fts5corrupt3.test.
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
  CREATE VIRTUAL TABLE t3 USING fts5vocab('t1'(),'col' );
} {/*malformed database schema*/}

do_catchsql_test 61.2 {
  SELECT * FROM t3 ORDER BY rowid;
} {/*malformed database schema*/}

breakpoint
#-------------------------------------------------------------------------
do_test 62.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
.open --hexdb
| size 28672 pagesize 4096 filename crash-44942694542e1e.db
| page 1 offset 0







<







8954
8955
8956
8957
8958
8959
8960

8961
8962
8963
8964
8965
8966
8967
  CREATE VIRTUAL TABLE t3 USING fts5vocab('t1'(),'col' );
} {/*malformed database schema*/}

do_catchsql_test 61.2 {
  SELECT * FROM t3 ORDER BY rowid;
} {/*malformed database schema*/}


#-------------------------------------------------------------------------
do_test 62.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
.open --hexdb
| size 28672 pagesize 4096 filename crash-44942694542e1e.db
| page 1 offset 0
10764
10765
10766
10767
10768
10769
10770

10771
10772
10773
10774
10775
10776
10777
  * FROM ttt('e* NOT ee*e* NOT ee* NOT ee*e* NOT e*') ;
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
reset_db
do_test 74.0 {
  sqlite3 db {}

  db deserialize [decode_hexdb {
| size 106496 pagesize 4096 filename x.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 1a   .....@  ........
|     32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04   ................
|     80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01   ................







>







10763
10764
10765
10766
10767
10768
10769
10770
10771
10772
10773
10774
10775
10776
10777
  * FROM ttt('e* NOT ee*e* NOT ee* NOT ee*e* NOT e*') ;
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
reset_db
do_test 74.0 {
  sqlite3 db {}
  sqlite3_fts5_register_matchinfo db
  db deserialize [decode_hexdb {
| size 106496 pagesize 4096 filename x.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 1a   .....@  ........
|     32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04   ................
|     80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01   ................
14583
14584
14585
14586
14587
14588
14589
14590
14591
14592
14593




14594
14595
14596
14597

14598
14599
14600
14601
14602
14603
14604
|   4032: b8 64 0a 02 34 02 03 b2 9a 9e 05 04 83 16 02 04   .d..4...........
|   4048: b4 a7 93 36 06 04 83 7d 03 02 ba 9c 02 04 83 07   ...6............
|   4064: 04 09 09 0a 0a 0c 0b 08 09 09 08 09 08 09 0a 0a   ................
|   4080: 0a 09 0a 0a 08 0a 08 09 0a 09 09 09 09 09 09 0a   ................
| end x.db
}]} {}

do_catchsql_test 74.1 {
  SELECT rowid, quote(matchinfo(t1,'p�xyb<s')) FROM t1 WHERE t1 MATCH 'e*';
} {1 {unable to use function matchinfo in the requested context}}





#-------------------------------------------------------------------------
reset_db
do_test 75.0 {
  sqlite3 db {}

  db deserialize [decode_hexdb {
| size 32768 pagesize 4096 filename crash-033d665d5caa8d.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00   .....@  ........
|     96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36   ...............6
|    112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 00 00 00 00 00 00   ...k............







|
|


>
>
>
>




>







14583
14584
14585
14586
14587
14588
14589
14590
14591
14592
14593
14594
14595
14596
14597
14598
14599
14600
14601
14602
14603
14604
14605
14606
14607
14608
14609
|   4032: b8 64 0a 02 34 02 03 b2 9a 9e 05 04 83 16 02 04   .d..4...........
|   4048: b4 a7 93 36 06 04 83 7d 03 02 ba 9c 02 04 83 07   ...6............
|   4064: 04 09 09 0a 0a 0c 0b 08 09 09 08 09 08 09 0a 0a   ................
|   4080: 0a 09 0a 0a 08 0a 08 09 0a 09 09 09 09 09 09 0a   ................
| end x.db
}]} {}

do_catchsql_test 74.0.5 {
  SELECT matchinfo(1,2);
} {1 {unable to use function matchinfo in the requested context}}

do_catchsql_test 74.1 {
  SELECT rowid, quote(matchinfo(t1,'pxyb<s')) FROM t1 WHERE t1 MATCH 'e*';
} {1 {unrecognized matchinfo flag: <}}

#-------------------------------------------------------------------------
reset_db
do_test 75.0 {
  sqlite3 db {}
  sqlite3_fts5_register_matchinfo db
  db deserialize [decode_hexdb {
| size 32768 pagesize 4096 filename crash-033d665d5caa8d.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00   .....@  ........
|     96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36   ...............6
|    112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 00 00 00 00 00 00   ...k............
14787
14788
14789
14790
14791
14792
14793
14794
14795
14796
14797
14798
14799
14800
14801
| page 8 offset 28672
|   4048: 00 00 00 00 00 00 5d 03 02 2b 69 6e 74 00 00 00   ......]..+int...
| end crash-033d665d5caa8d.db
}]} {}

do_catchsql_test 75.1 {
  SELECT rowid, quote(matchinfo(t1,'pcxybs')) FROM t1 WHERE t1 MATCH 'e*';
} {1 {unable to use function matchinfo in the requested context}}

#-------------------------------------------------------------------------
reset_db
do_test 76.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 40960 pagesize 4096 filename crash-03b68c01d30713.db







|







14792
14793
14794
14795
14796
14797
14798
14799
14800
14801
14802
14803
14804
14805
14806
| page 8 offset 28672
|   4048: 00 00 00 00 00 00 5d 03 02 2b 69 6e 74 00 00 00   ......]..+int...
| end crash-033d665d5caa8d.db
}]} {}

do_catchsql_test 75.1 {
  SELECT rowid, quote(matchinfo(t1,'pcxybs')) FROM t1 WHERE t1 MATCH 'e*';
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
reset_db
do_test 76.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 40960 pagesize 4096 filename crash-03b68c01d30713.db
Changes to ext/fts5/test/fts5eb.test.
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
}

do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61');
  INSERT INTO e1 VALUES ('just a few words with a / inside');
}
do_execsql_test 3.1 {
  SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank;
} {1 -1e-06}
do_execsql_test 3.2 {
  SELECT rowid FROM e1 WHERE e1 MATCH '"/" OR "just"'
} 1
do_execsql_test 3.3 {
  SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank;
} {1 -1e-06}

do_execsql_test 3.4 "
  SELECT fts5_expr_tcl('e AND \" \"');
" {{AND [nearset -- {e}] [{}]}}









|





|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
}

do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61');
  INSERT INTO e1 VALUES ('just a few words with a / inside');
}
do_execsql_test 3.1 {
  SELECT rowid, format('%g',bm25(e1)) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank;
} {1 -1e-06}
do_execsql_test 3.2 {
  SELECT rowid FROM e1 WHERE e1 MATCH '"/" OR "just"'
} 1
do_execsql_test 3.3 {
  SELECT rowid, format('%g',bm25(e1)) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank;
} {1 -1e-06}

do_execsql_test 3.4 "
  SELECT fts5_expr_tcl('e AND \" \"');
" {{AND [nearset -- {e}] [{}]}}


Added ext/fts5/test/fts5expr.test.
































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 2024 August 8
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the FTS5 module.
#

source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5expr

# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
  finish_test
  return
}

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING fts5(a);
  INSERT INTO x1(rowid, a) VALUES (113, 'fts5 expr test');
}

do_execsql_test 1.1 {
  SELECT rowid FROM x1('expr');
} {113}

for {set ii 0} {$ii < 300} {incr ii} {
  set expr "expr "
  append expr [string repeat "NOT abcd " $ii]

  if {$ii<257} {
    set res {0 113}
  } else {
    set res {1 {fts5 expression tree is too large (maximum depth 256)}}
  }
  do_catchsql_test 1.1.$ii {
    SELECT rowid FROM x1($expr)
  } $res
}

finish_test

Changes to ext/fts5/test/fts5first.test.
18
19
20
21
22
23
24

25
26
27
28
29
30
31
}


do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING fts5(a, b);
}


foreach {tn expr ok} {
  1 {^abc}           1
  2 {^abc + def}     1
  3 {^ "abc def"}    1
  4 {^"abc def"}     1
  5 {abc ^def}       1
  6 {abc + ^def}     0







>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
}


do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING fts5(a, b);
}

unset -nocomplain res
foreach {tn expr ok} {
  1 {^abc}           1
  2 {^abc + def}     1
  3 {^ "abc def"}    1
  4 {^"abc def"}     1
  5 {abc ^def}       1
  6 {abc + ^def}     0
Changes to ext/fts5/test/fts5integrity.test.
149
150
151
152
153
154
155

156
157
158
159
160
161
162
  INSERT INTO gg(gg) VALUES('optimize');
}

do_execsql_test 5.3 {
  INSERT INTO gg(gg) VALUES('integrity-check');
}


do_test 5.4.1 {
  set ok 0
  for {set i 0} {$i < 10000} {incr i} {
    set T [format %.5d $i]
    set res  [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC  }]
    set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }]
    if {$res == [lsort -integer $res2]} { incr ok }







>







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  INSERT INTO gg(gg) VALUES('optimize');
}

do_execsql_test 5.3 {
  INSERT INTO gg(gg) VALUES('integrity-check');
}

unset -nocomplain res
do_test 5.4.1 {
  set ok 0
  for {set i 0} {$i < 10000} {incr i} {
    set T [format %.5d $i]
    set res  [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC  }]
    set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }]
    if {$res == [lsort -integer $res2]} { incr ok }
Changes to ext/fts5/test/fts5interrupt.test.
29
30
31
32
33
34
35

36
37
38
39
40
41
42

proc progress_handler {args} {
  incr ::progress_handler_delay -1
  if {$::progress_handler_delay<=0} { return 1 } 
  return 0
}


foreach {tn sql} {
  1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') }
  2 { COMMIT }
} {
  set bDone 0
  for {set i 1} {$bDone==0} {incr i} {
    do_test 1.$tn.$i {







>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

proc progress_handler {args} {
  incr ::progress_handler_delay -1
  if {$::progress_handler_delay<=0} { return 1 } 
  return 0
}

unset -nocomplain res
foreach {tn sql} {
  1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') }
  2 { COMMIT }
} {
  set bDone 0
  for {set i 1} {$bDone==0} {incr i} {
    do_test 1.$tn.$i {
60
61
62
63
64
65
66
67
      }
      set {} {}
    } {}
  }
}

finish_test








<
61
62
63
64
65
66
67

      }
      set {} {}
    } {}
  }
}

finish_test

Changes to ext/fts5/test/fts5restart.test.
25
26
27
28
29
30
31

32
33
34
35
36
37
38
  CREATE VIRTUAL TABLE f1 USING fts5(ff);
}

#-------------------------------------------------------------------------
# Run the 'optimize' command. Check that it does not disturb ongoing
# full-text queries.
#

do_test 1.1 {
  for {set i 1} {$i < 1000} {incr i} {
    execsql { INSERT INTO f1 VALUES('a b c d e') }
    lappend lRowid $i
  }
} {}








>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  CREATE VIRTUAL TABLE f1 USING fts5(ff);
}

#-------------------------------------------------------------------------
# Run the 'optimize' command. Check that it does not disturb ongoing
# full-text queries.
#
unset -nocomplain lRowid
do_test 1.1 {
  for {set i 1} {$i < 1000} {incr i} {
    execsql { INSERT INTO f1 VALUES('a b c d e') }
    lappend lRowid $i
  }
} {}

Changes to ext/fts5/test/fts5tokenizer2.test.
80
81
82
83
84
85
86




















87
88
89
do_execsql_test 1.6 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('mess');
} {AAdontBB>mess<}

do_execsql_test 1.7 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('BB mess');
} {AAdont>BBmess<}






















finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
do_execsql_test 1.6 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('mess');
} {AAdontBB>mess<}

do_execsql_test 1.7 {
  SELECT highlight(t1, 0, '>', '<') FROM t1('BB mess');
} {AAdont>BBmess<}

# 2024-08-06 https://sqlite.org/forum/forumpost/171bcc2bcd
# Error handling of tokenize= arguments.
#
foreach {n tkz} {
  1  {ascii none}
  2  {unicode61 none}
  3  {porter none}
  4  {trigram none}
  5  {ascii none 0}
  6  {unicode61 none 0}
  7  {porter none 0}
  8  {trigram none 0}
} {
  db eval {DROP TABLE IF EXISTS t2;}
  do_catchsql_test 2.$n "
     DROP TABLE IF EXISTS t2;
     CREATE VIRTUAL TABLE t2 USING fts5(a,b,c,tokenize='$tkz');
  " {1 {error in tokenizer constructor}}
}


finish_test
Changes to ext/fts5/test/fts5trigram.test.
65
66
67
68
69
70
71



72
73
74
75
76
77
78
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize="trigram case_sensitive 1");
  INSERT INTO t1 VALUES('abcdefghijklm');
  INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}




foreach {tn s res} {
  1 abc           "(abc)defghijklm"
  2 defgh         "abc(defgh)ijklm"
  3 abcdefghijklm "(abcdefghijklm)"
  4 กรุ            "(กรุ)งเทพมหานคร"
  5 งเทพมห        "กรุ(งเทพมห)านคร"







>
>
>







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize="trigram case_sensitive 1");
  INSERT INTO t1 VALUES('abcdefghijklm');
  INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
do_catchsql_test 2.0.1 {
  CREATE VIRTUAL TABLE t2 USING fts5(z, tokenize='trigram case_sensitive');
} {1 {error in tokenizer constructor}}

foreach {tn s res} {
  1 abc           "(abc)defghijklm"
  2 defgh         "abc(defgh)ijklm"
  3 abcdefghijklm "(abcdefghijklm)"
  4 กรุ            "(กรุ)งเทพมหานคร"
  5 งเทพมห        "กรุ(งเทพมห)านคร"
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
do_execsql_test 7.0 {
  CREATE VIRTUAL TABLE f USING FTS5(filename, tokenize="trigram");
  INSERT INTO f (rowid, filename) VALUES 
      (10, "giraffe.png"), 
      (20, "жираф.png"), 
      (30, "cat.png"), 
      (40, "кот.png"), 
      (50, "misic-🎵-.mp3");
}
do_execsql_test 7.1 {
  SELECT rowid FROM f WHERE +filename GLOB '*ир*';
} {20}
do_execsql_test 7.2 {
  SELECT rowid FROM f WHERE filename GLOB '*ир*';
} {20}







|







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
do_execsql_test 7.0 {
  CREATE VIRTUAL TABLE f USING FTS5(filename, tokenize="trigram");
  INSERT INTO f (rowid, filename) VALUES 
      (10, "giraffe.png"), 
      (20, "жираф.png"), 
      (30, "cat.png"), 
      (40, "кот.png"), 
      (50, "misic-🎵-.mp3");
}
do_execsql_test 7.1 {
  SELECT rowid FROM f WHERE +filename GLOB '*ир*';
} {20}
do_execsql_test 7.2 {
  SELECT rowid FROM f WHERE filename GLOB '*ир*';
} {20}
Changes to ext/fts5/test/fts5trigram2.test.
17
18
19
20
21
22
23



24
25
26
27
28
29
30
set ::testprefix fts5trigram2

do_execsql_test 1.0 "
  CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize='trigram remove_diacritics 1');
  INSERT INTO t1 VALUES('abc\u0303defghijklm');
  INSERT INTO t1 VALUES('a\u0303b\u0303c\u0303defghijklm');
"




do_execsql_test 1.1 {
  SELECT highlight(t1, 0, '(', ')') FROM t1('abc');
} [list \
  "(abc\u0303)defghijklm"                          \
  "(a\u0303b\u0303c\u0303)defghijklm"              \
]







>
>
>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
set ::testprefix fts5trigram2

do_execsql_test 1.0 "
  CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize='trigram remove_diacritics 1');
  INSERT INTO t1 VALUES('abc\u0303defghijklm');
  INSERT INTO t1 VALUES('a\u0303b\u0303c\u0303defghijklm');
"
do_catchsql_test 1.0.1 {
  CREATE VIRTUAL TABLE t2 USING fts5(z, tokenize='trigram remove_diacritics');
} {1 {error in tokenizer constructor}}

do_execsql_test 1.1 {
  SELECT highlight(t1, 0, '(', ')') FROM t1('abc');
} [list \
  "(abc\u0303)defghijklm"                          \
  "(a\u0303b\u0303c\u0303)defghijklm"              \
]
112
113
114
115
116
117
118
119














120
do_eqp_test 4.1 {
  SELECT rowid FROM t4 WHERE z LIKE '%abc%'
} {VIRTUAL TABLE INDEX 0:L0}

do_execsql_test 4.2 {
  SELECT rowid FROM t4 WHERE z LIKE '%abc%'
} {1}















finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
do_eqp_test 4.1 {
  SELECT rowid FROM t4 WHERE z LIKE '%abc%'
} {VIRTUAL TABLE INDEX 0:L0}

do_execsql_test 4.2 {
  SELECT rowid FROM t4 WHERE z LIKE '%abc%'
} {1}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
  CREATE VIRTUAL TABLE t5 USING fts5(
      c1, tokenize='trigram', detail='none'
  );
  INSERT INTO t5(rowid, c1) VALUES(1, 'abc_____xyx_yxz');
  INSERT INTO t5(rowid, c1) VALUES(2, 'abc_____xyxz');
  INSERT INTO t5(rowid, c1) VALUES(3, 'ac_____xyxz');
} {}
do_execsql_test 5.1 {
  SELECT rowid FROM t5 WHERE c1 LIKE 'abc%xyxz'
} {2}

finish_test
Changes to ext/fts5/test/fts5unicode.test.
56
57
58
59
60
61
62

63
64
65
66
67
68
69
" {t1 t2}

#-------------------------------------------------------------------------
# Check that codepoints that require 4 bytes to store in utf-8 (those that
# require 17 or more bits to store).
#


set A [db one {SELECT char(0x1F75E)}]    ;# Type So
set B [db one {SELECT char(0x1F5FD)}]    ;# Type So
set C [db one {SELECT char(0x2F802)}]    ;# Type Lo
set D [db one {SELECT char(0x2F808)}]    ;# Type Lo

do_execsql_test 3.0 "
  CREATE VIRTUAL TABLE xyz USING fts5(x,







>







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
" {t1 t2}

#-------------------------------------------------------------------------
# Check that codepoints that require 4 bytes to store in utf-8 (those that
# require 17 or more bits to store).
#

unset -nocomplain A B C D
set A [db one {SELECT char(0x1F75E)}]    ;# Type So
set B [db one {SELECT char(0x1F5FD)}]    ;# Type So
set C [db one {SELECT char(0x2F802)}]    ;# Type Lo
set D [db one {SELECT char(0x2F808)}]    ;# Type Lo

do_execsql_test 3.0 "
  CREATE VIRTUAL TABLE xyz USING fts5(x,
Changes to ext/fts5/test/fts5unicode2.test.
112
113
114
115
116
117
118

119
120
121
122
123
124
125
  Improvements to the handling of CSV inputs in the command-line shell
} {
  Fix a bug introduced in version 3.7.10 that might cause a LEFT JOIN to be
  incorrectly converted into an INNER JOIN if the WHERE clause indexable terms
  connected by OR.  
}]


set map(a) [list "\u00C4" "\u00E4"]  ; # LATIN LETTER A WITH DIAERESIS
set map(e) [list "\u00CB" "\u00EB"]  ; # LATIN LETTER E WITH DIAERESIS
set map(i) [list "\u00CF" "\u00EF"]  ; # LATIN LETTER I WITH DIAERESIS
set map(o) [list "\u00D6" "\u00F6"]  ; # LATIN LETTER O WITH DIAERESIS
set map(u) [list "\u00DC" "\u00FC"]  ; # LATIN LETTER U WITH DIAERESIS
set map(y) [list "\u0178" "\u00FF"]  ; # LATIN LETTER Y WITH DIAERESIS
set map(h) [list "\u1E26" "\u1E27"]  ; # LATIN LETTER H WITH DIAERESIS







>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  Improvements to the handling of CSV inputs in the command-line shell
} {
  Fix a bug introduced in version 3.7.10 that might cause a LEFT JOIN to be
  incorrectly converted into an INNER JOIN if the WHERE clause indexable terms
  connected by OR.  
}]

unset -nocomplain map
set map(a) [list "\u00C4" "\u00E4"]  ; # LATIN LETTER A WITH DIAERESIS
set map(e) [list "\u00CB" "\u00EB"]  ; # LATIN LETTER E WITH DIAERESIS
set map(i) [list "\u00CF" "\u00EF"]  ; # LATIN LETTER I WITH DIAERESIS
set map(o) [list "\u00D6" "\u00F6"]  ; # LATIN LETTER O WITH DIAERESIS
set map(u) [list "\u00DC" "\u00FC"]  ; # LATIN LETTER U WITH DIAERESIS
set map(y) [list "\u0178" "\u00FF"]  ; # LATIN LETTER Y WITH DIAERESIS
set map(h) [list "\u1E26" "\u1E27"]  ; # LATIN LETTER H WITH DIAERESIS
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
do_execsql_test 8.2.2 {
  SELECT rowid FROM t4 WHERE t4 MATCH 'o' ORDER BY rowid ASC;
} {1 3}
do_execsql_test 8.2.3 {
  SELECT rowid FROM t4 WHERE t4 MATCH 'a' ORDER BY rowid ASC;
} {2 4}

#-------------------------------------------------------------------------
#
if 0 {
foreach {tn sql} {
  1 {
    CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 [tokenchars= .]);
    CREATE VIRTUAL TABLE t6 USING fts4(
        tokenize=unicode61 [tokenchars=="] "tokenchars=[]");
    CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 [separators=x\xC4]);
  }
  2 {
    CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 "tokenchars= .");
    CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 "tokenchars=[=""]");
    CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 "separators=x\xC4");
  }
  3 {
    CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 'tokenchars= .');
    CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 'tokenchars=="[]');
    CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 'separators=x\xC4');
  }
  4 {
    CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 `tokenchars= .`);
    CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 `tokenchars=[="]`);
    CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 `separators=x\xC4`);
  }
} {
  do_execsql_test 9.$tn.0 { 
    DROP TABLE IF EXISTS t5;
    DROP TABLE IF EXISTS t5aux;
    DROP TABLE IF EXISTS t6;
    DROP TABLE IF EXISTS t6aux;
    DROP TABLE IF EXISTS t7;
    DROP TABLE IF EXISTS t7aux;
  }
  do_execsql_test 9.$tn.1 $sql

  do_execsql_test 9.$tn.2 {
    CREATE VIRTUAL TABLE t5aux USING fts4aux(t5);
    INSERT INTO t5 VALUES('one two three/four.five.six');
    SELECT * FROM t5aux;
  } {
    four.five.six   * 1 1 four.five.six   0 1 1 
    {one two three} * 1 1 {one two three} 0 1 1
  }

  do_execsql_test 9.$tn.3 {
    CREATE VIRTUAL TABLE t6aux USING fts4aux(t6);
    INSERT INTO t6 VALUES('alpha=beta"gamma/delta[epsilon]zeta');
    SELECT * FROM t6aux;
  } {
    {alpha=beta"gamma}   * 1 1 {alpha=beta"gamma} 0 1 1 
    {delta[epsilon]zeta} * 1 1 {delta[epsilon]zeta} 0 1 1
  }

  do_execsql_test 9.$tn.4 {
    CREATE VIRTUAL TABLE t7aux USING fts4aux(t7);
    INSERT INTO t7 VALUES('alephxbeth\xC4gimel');
    SELECT * FROM t7aux;
  } {
    aleph * 1 1 aleph 0 1 1 
    beth  * 1 1 beth  0 1 1 
    gimel * 1 1 gimel 0 1 1
  }
}

# Check that multiple options are handled correctly.
#
do_execsql_test 10.1 {
  DROP TABLE IF EXISTS t1;
  CREATE VIRTUAL TABLE t1 USING fts4(tokenize=unicode61
    "tokenchars=xyz" "tokenchars=.=" "separators=.=" "separators=xy"
    "separators=a" "separators=a" "tokenchars=a" "tokenchars=a"
  );

  INSERT INTO t1 VALUES('oneatwoxthreeyfour');
  INSERT INTO t1 VALUES('a.single=word');
  CREATE VIRTUAL TABLE t1aux USING fts4aux(t1);
  SELECT * FROM t1aux;
} {
  .single=word * 1 1 .single=word 0 1 1 
  four         * 1 1 four         0 1 1 
  one          * 1 1 one          0 1 1 
  three        * 1 1 three        0 1 1 
  two          * 1 1 two          0 1 1
}

# Test that case folding happens after tokenization, not before.
#
do_execsql_test 10.2 {
  DROP TABLE IF EXISTS t2;
  CREATE VIRTUAL TABLE t2 USING fts4(tokenize=unicode61 "separators=aB");
  INSERT INTO t2 VALUES('oneatwoBthree');
  INSERT INTO t2 VALUES('onebtwoAthree');
  CREATE VIRTUAL TABLE t2aux USING fts4aux(t2);
  SELECT * FROM t2aux;
} {
  one           * 1 1 one           0 1 1 
  onebtwoathree * 1 1 onebtwoathree 0 1 1 
  three         * 1 1 three         0 1 1 
  two           * 1 1 two           0 1 1
}

# Test that the tokenchars and separators options work with the 
# fts3tokenize table.
#
do_execsql_test 11.1 {
  CREATE VIRTUAL TABLE ft1 USING fts3tokenize(
    "unicode61", "tokenchars=@.", "separators=1234567890"
  );
  SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road';
} {
  berlin@street sydney.road
}

}

finish_test







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

466
467
468
469
470
471
472




















































































































473
do_execsql_test 8.2.2 {
  SELECT rowid FROM t4 WHERE t4 MATCH 'o' ORDER BY rowid ASC;
} {1 3}
do_execsql_test 8.2.3 {
  SELECT rowid FROM t4 WHERE t4 MATCH 'a' ORDER BY rowid ASC;
} {2 4}





















































































































finish_test
Changes to ext/fts5/test/fts5vocab.test.
509
510
511
512
513
514
515

516
517
518
519
520
521
522
    INSERT INTO ft(a) VALUES('4 5 6');
    INSERT INTO ft(a) VALUES('1 2 3');
    INSERT INTO ft(a) VALUES('4 5 6');
    INSERT INTO ft(a) VALUES('1 2 3');
    INSERT INTO ft(a) VALUES('4 5 6');
}


do_test 10.6 {
  set res [list]
  db eval { SELECT rowid FROM ft('4') } x {
    db eval { SELECT * FROM t2 }
    lappend res $x(rowid)
  }
  db eval COMMIT







>







509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
    INSERT INTO ft(a) VALUES('4 5 6');
    INSERT INTO ft(a) VALUES('1 2 3');
    INSERT INTO ft(a) VALUES('4 5 6');
    INSERT INTO ft(a) VALUES('1 2 3');
    INSERT INTO ft(a) VALUES('4 5 6');
}

unset -nocomplain x res
do_test 10.6 {
  set res [list]
  db eval { SELECT rowid FROM ft('4') } x {
    db eval { SELECT * FROM t2 }
    lappend res $x(rowid)
  }
  db eval COMMIT
Changes to ext/intck/test_intck.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"
#include "sqlite3intck.h"

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

#include <string.h>
#include <assert.h>

/* In test1.c */
int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
const char *sqlite3ErrName(int);








<
<
<
<
|
<
<







11
12
13
14
15
16
17




18


19
20
21
22
23
24
25
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"
#include "sqlite3intck.h"




#include "tclsqlite.h"


#include <string.h>
#include <assert.h>

/* In test1.c */
int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
const char *sqlite3ErrName(int);

Changes to ext/rbu/test_rbu.c.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#include "sqlite3.h"

#if defined(SQLITE_TEST)
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)

#include "sqlite3rbu.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif
#include <assert.h>
#include <string.h>

typedef struct TestRbu TestRbu;
struct TestRbu {
  sqlite3rbu *pRbu;
  Tcl_Interp *interp;







<
<
<
|
<
<
<
<







13
14
15
16
17
18
19



20




21
22
23
24
25
26
27

#include "sqlite3.h"

#if defined(SQLITE_TEST)
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)

#include "sqlite3rbu.h"



#include "tclsqlite.h"




#include <assert.h>
#include <string.h>

typedef struct TestRbu TestRbu;
struct TestRbu {
  sqlite3rbu *pRbu;
  Tcl_Interp *interp;
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
  }
  return TCL_OK;
}

#else
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
int SqliteRbu_Init(Tcl_Interp *interp){ return TCL_OK; }
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
#endif /* defined(SQLITE_TEST) */







<
<
<
|
<



421
422
423
424
425
426
427



428

429
430
431
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
  }
  return TCL_OK;
}

#else



#include "tclsqlite.h"

int SqliteRbu_Init(Tcl_Interp *interp){ return TCL_OK; }
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
#endif /* defined(SQLITE_TEST) */
Changes to ext/recover/dbdata.c.
675
676
677
678
679
680
681

682
683
684
685
686
687
688
          }else{

            /* Allocate space for payload. And a bit more to catch small buffer
            ** overruns caused by attempting to read a varint or similar from 
            ** near the end of a corrupt record.  */
            rc = dbdataBufferSize(&pCsr->rec, nPayload+DBDATA_PADDING_BYTES);
            if( rc!=SQLITE_OK ) return rc;

            assert( nPayload!=0 );

            /* Load the nLocal bytes of payload */
            memcpy(pCsr->rec.aBuf, &pCsr->aPage[iOff], nLocal);
            iOff += nLocal;

            /* Load content from overflow pages */







>







675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
          }else{

            /* Allocate space for payload. And a bit more to catch small buffer
            ** overruns caused by attempting to read a varint or similar from 
            ** near the end of a corrupt record.  */
            rc = dbdataBufferSize(&pCsr->rec, nPayload+DBDATA_PADDING_BYTES);
            if( rc!=SQLITE_OK ) return rc;
            assert( pCsr->rec.aBuf!=0 );
            assert( nPayload!=0 );

            /* Load the nLocal bytes of payload */
            memcpy(pCsr->rec.aBuf, &pCsr->aPage[iOff], nLocal);
            iOff += nLocal;

            /* Load content from overflow pages */
Changes to ext/recover/recovercorrupt4.test.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  }
  
  db close
  
  do_test 1.1 {
    set sz [expr [file size test.db] - 1024]
    set fd [open test.db]
    fconfigure $fd -encoding binary -translation binary
  
    set data [read $fd $sz]
    set fd2 [open test.db2 w]
    fconfigure $fd2 -encoding binary -translation binary
    puts -nonewline $fd2 $data
    close $fd2
    set {} {}
  } {}
  
  do_test 1.2 {
    forcedelete test.db3







|



|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  }
  
  db close
  
  do_test 1.1 {
    set sz [expr [file size test.db] - 1024]
    set fd [open test.db]
    fconfigure $fd -translation binary
  
    set data [read $fd $sz]
    set fd2 [open test.db2 w]
    fconfigure $fd2 -translation binary
    puts -nonewline $fd2 $data
    close $fd2
    set {} {}
  } {}
  
  do_test 1.2 {
    forcedelete test.db3
57
58
59
60
61
62
63
64
    execsql {
      SELECT indexed, unindexed FROM rows
    }
  } {1 1 2 2 4 4 8 8}
}

finish_test








<
57
58
59
60
61
62
63

    execsql {
      SELECT indexed, unindexed FROM rows
    }
  } {1 1 2 2 4 4 8 8}
}

finish_test

Changes to ext/recover/recoverpgsz.test.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
      UPDATE t1 SET c = randomblob(100000);
    }
  }
  db close


  set fd [open test.db]
  fconfigure $fd -encoding binary -translation binary
  seek $fd $pgsz
  set pg1 [read $fd $pgsz]
  set pg2 [read $fd $pgsz]
  close $fd

  set fd2 [open test.db2 w]
  fconfigure $fd2 -encoding binary -translation binary
  seek $fd2 $pgsz
  puts -nonewline $fd2 $pg1
  close $fd2

  sqlite3 db2 test.db2
  do_test 1.$pgsz.$bOverflow.2 {
    set R [sqlite3_recover_init db2 main test.db3]







|






|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
      UPDATE t1 SET c = randomblob(100000);
    }
  }
  db close


  set fd [open test.db]
  fconfigure $fd -translation binary
  seek $fd $pgsz
  set pg1 [read $fd $pgsz]
  set pg2 [read $fd $pgsz]
  close $fd

  set fd2 [open test.db2 w]
  fconfigure $fd2 -translation binary
  seek $fd2 $pgsz
  puts -nonewline $fd2 $pg1
  close $fd2

  sqlite3 db2 test.db2
  do_test 1.$pgsz.$bOverflow.2 {
    set R [sqlite3_recover_init db2 main test.db3]
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  db2 close
  db3 close

  forcedelete test.db3
  forcedelete test.db2

  set fd2 [open test.db2 w]
  fconfigure $fd2 -encoding binary -translation binary
  seek $fd2 $pgsz
  puts -nonewline $fd2 $pg2
  close $fd2

  sqlite3 db2 test.db2
  do_test 1.$pgsz.$bOverflow.4 {
    set R [sqlite3_recover_init db2 main test.db3]







|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  db2 close
  db3 close

  forcedelete test.db3
  forcedelete test.db2

  set fd2 [open test.db2 w]
  fconfigure $fd2 -translation binary
  seek $fd2 $pgsz
  puts -nonewline $fd2 $pg2
  close $fd2

  sqlite3 db2 test.db2
  do_test 1.$pgsz.$bOverflow.4 {
    set R [sqlite3_recover_init db2 main test.db3]
91
92
93
94
95
96
97
98
99
100

  db2 close
  db3 close
}


finish_test










<
<
<
91
92
93
94
95
96
97




  db2 close
  db3 close
}


finish_test



Changes to ext/recover/sqlite3recover.c.
359
360
361
362
363
364
365
366
367

368
369
370
371
372
373
374
  const char *zFmt, ...
){
  char *z = 0;
  va_list ap;
  va_start(ap, zFmt);
  if( zFmt ){
    z = sqlite3_vmprintf(zFmt, ap);
    va_end(ap);
  }

  sqlite3_free(p->zErrMsg);
  p->zErrMsg = z;
  p->errCode = errCode;
  return errCode;
}









<

>







359
360
361
362
363
364
365

366
367
368
369
370
371
372
373
374
  const char *zFmt, ...
){
  char *z = 0;
  va_list ap;
  va_start(ap, zFmt);
  if( zFmt ){
    z = sqlite3_vmprintf(zFmt, ap);

  }
  va_end(ap);
  sqlite3_free(p->zErrMsg);
  p->zErrMsg = z;
  p->errCode = errCode;
  return errCode;
}


Changes to ext/recover/test_recover.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
*************************************************************************
**
*/

#include "sqlite3recover.h"
#include "sqliteInt.h"

#include <tcl.h>
#include <assert.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

typedef struct TestRecover TestRecover;
struct TestRecover {
  sqlite3_recover *p;







<
|







10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
**
*************************************************************************
**
*/

#include "sqlite3recover.h"
#include "sqliteInt.h"

#include "tclsqlite.h"
#include <assert.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

typedef struct TestRecover TestRecover;
struct TestRecover {
  sqlite3_recover *p;
304
305
306
307
308
309
310
311
  for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){
    struct Cmd *p = &aCmd[i];
    Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, p->pArg, 0);
  }
#endif
  return TCL_OK;
}








<
303
304
305
306
307
308
309

  for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){
    struct Cmd *p = &aCmd[i];
    Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, p->pArg, 0);
  }
#endif
  return TCL_OK;
}

Changes to ext/rtree/test_rtreedoc.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"

#ifdef SQLITE_ENABLE_RTREE

typedef struct BoxGeomCtx BoxGeomCtx;







<
<
<
|
<







10
11
12
13
14
15
16



17

18
19
20
21
22
23
24
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"



#include "tclsqlite.h"


/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"

#ifdef SQLITE_ENABLE_RTREE

typedef struct BoxGeomCtx BoxGeomCtx;
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
    sqlite3_snprintf(sizeof(aPtr)-1, aPtr, "%p", (void*)p);
    Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(aPtr,-1));

    rc = Tcl_EvalObjEx(interp, pScript, 0);
    if( rc!=TCL_OK ){
      rc = SQLITE_ERROR;
    }else{
      int nObj = 0;
      Tcl_Obj **aObj = 0;

      pRes = Tcl_GetObjResult(interp);
      if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) ) return TCL_ERROR;
      if( nObj>0 ){
        const char *zCmd = Tcl_GetString(aObj[0]);
        if( 0==sqlite3_stricmp(zCmd, "zero") ){







|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    sqlite3_snprintf(sizeof(aPtr)-1, aPtr, "%p", (void*)p);
    Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(aPtr,-1));

    rc = Tcl_EvalObjEx(interp, pScript, 0);
    if( rc!=TCL_OK ){
      rc = SQLITE_ERROR;
    }else{
      Tcl_Size nObj = 0;
      Tcl_Obj **aObj = 0;

      pRes = Tcl_GetObjResult(interp);
      if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) ) return TCL_ERROR;
      if( nObj>0 ){
        const char *zCmd = Tcl_GetString(aObj[0]);
        if( 0==sqlite3_stricmp(zCmd, "zero") ){
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  );

  Tcl_ListObjAppendElement(interp, pEval, pArg);
  rc = Tcl_EvalObjEx(interp, pEval, 0) ? SQLITE_ERROR : SQLITE_OK;

  if( rc==SQLITE_OK ){
    double rScore = 0.0;
    int nObj = 0;
    int eP = 0;
    Tcl_Obj **aObj = 0;
    Tcl_Obj *pRes = Tcl_GetObjResult(interp);

    if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) 
     || nObj!=2 
     || Tcl_GetDoubleFromObj(interp, aObj[1], &rScore)







|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  );

  Tcl_ListObjAppendElement(interp, pEval, pArg);
  rc = Tcl_EvalObjEx(interp, pEval, 0) ? SQLITE_ERROR : SQLITE_OK;

  if( rc==SQLITE_OK ){
    double rScore = 0.0;
    Tcl_Size nObj = 0;
    int eP = 0;
    Tcl_Obj **aObj = 0;
    Tcl_Obj *pRes = Tcl_GetObjResult(interp);

    if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) 
     || nObj!=2 
     || Tcl_GetDoubleFromObj(interp, aObj[1], &rScore)
Changes to ext/session/changesetfuzz1.test.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
if {$CF==""} {
  finish_test
  return
}

proc writefile {zFile data} {
  set fd [open $zFile w]
  fconfigure $fd -translation binary -encoding binary
  puts -nonewline $fd $data
  close $fd
}

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b, c, d, PRIMARY KEY(c, d));
  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
if {$CF==""} {
  finish_test
  return
}

proc writefile {zFile data} {
  set fd [open $zFile w]
  fconfigure $fd -translation binary
  puts -nonewline $fd $data
  close $fd
}

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b, c, d, PRIMARY KEY(c, d));
  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
77
78
79
80
81
82
83
84
      forcecopy input.patchset-0 input.patchset
    }
  }
} {}


finish_test








<
77
78
79
80
81
82
83

      forcecopy input.patchset-0 input.patchset
    }
  }
} {}


finish_test

Changes to ext/session/session4.test.
1
2
3
4
5
6
7
8
9
10
11
12
13

14


15
16
17
18
19
20
21
# 2011 March 25
#
# 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 the session module. 
# 


package require Tcl 8.6



if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
} 
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}













>
|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2011 March 25
#
# 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 the session module. 
# 

if {$tcl_version<8.6} {
  puts "This module requires Tcl 8.6 or later"
  return
}

if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
} 
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  54 540101743400120003001200010000000000000002120002400C000000000002120002400C00000000000050040100000074310017FF0050040100000074310017FF7F00000000000000050100000000000000030100000003001700010000666F7572
  55 540101743400120003001200010000000000000002120002400C00000000000050040100000074310017000100010080000001000000020003010100000300170100000003001700010000666F7572
  56 5487ffffff7f
} {
  do_test 2.$tn {
    set changeset [binary decode hex $blob]
#set fd [open x.change w+]
#fconfigure $fd -encoding binary -translation binary
#puts -nonewline $fd $changeset
#close $fd
    list [catch { sqlite3changeset_apply db $changeset xConflict } msg] $msg
  } {1 SQLITE_CORRUPT}
}

finish_test







|







135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  54 540101743400120003001200010000000000000002120002400C000000000002120002400C00000000000050040100000074310017FF0050040100000074310017FF7F00000000000000050100000000000000030100000003001700010000666F7572
  55 540101743400120003001200010000000000000002120002400C00000000000050040100000074310017000100010080000001000000020003010100000300170100000003001700010000666F7572
  56 5487ffffff7f
} {
  do_test 2.$tn {
    set changeset [binary decode hex $blob]
#set fd [open x.change w+]
#fconfigure $fd -translation binary
#puts -nonewline $fd $changeset
#close $fd
    list [catch { sqlite3changeset_apply db $changeset xConflict } msg] $msg
  } {1 SQLITE_CORRUPT}
}

finish_test
Changes to ext/session/sessiondiff.test.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  dbtmp close

  md5 $txt
}

proc readfile {filename} {
  set fd [open $filename]
  fconfigure $fd -translation binary -encoding binary
  set data [read $fd]
  close $fd
  set data
}

proc get_changeset {db1 db2} {
  exec $::PROG --changeset changeset.bin $db1 $db2







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  dbtmp close

  md5 $txt
}

proc readfile {filename} {
  set fd [open $filename]
  fconfigure $fd -translation binary
  set data [read $fd]
  close $fd
  set data
}

proc get_changeset {db1 db2} {
  exec $::PROG --changeset changeset.bin $db1 $db2
Changes to ext/session/sessionfault.test.
363
364
365
366
367
368
369

370
371
372
373
374
375
376

faultsim_delete_and_reopen
do_execsql_test 7.prep1 {
  CREATE TABLE t1(a, b, PRIMARY KEY(a));
}
faultsim_save_and_close


set res [list]
for {set ::i 0} {$::i < 480} {incr ::i 4} {
  lappend res "INSERT t1 0 X. {} {i $::i i $::i}"
}
set res [lsort $res]
do_faultsim_test 7 -faults oom-transient -prep {
  catch { S delete }







>







363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

faultsim_delete_and_reopen
do_execsql_test 7.prep1 {
  CREATE TABLE t1(a, b, PRIMARY KEY(a));
}
faultsim_save_and_close

unset -nocomplain res
set res [list]
for {set ::i 0} {$::i < 480} {incr ::i 4} {
  lappend res "INSERT t1 0 X. {} {i $::i i $::i}"
}
set res [lsort $res]
do_faultsim_test 7 -faults oom-transient -prep {
  catch { S delete }
Changes to ext/session/test_session.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_SESSION) \
 && defined(SQLITE_ENABLE_PREUPDATE_HOOK)

#include "sqlite3session.h"
#include <assert.h>
#include <string.h>
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

#ifndef SQLITE_AMALGAMATION
  typedef unsigned char u8;
#endif

typedef struct TestSession TestSession;
struct TestSession {







<
<
<
|
<
<
<
<







1
2
3
4
5
6
7



8




9
10
11
12
13
14
15

#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_SESSION) \
 && defined(SQLITE_ENABLE_PREUPDATE_HOOK)

#include "sqlite3session.h"
#include <assert.h>
#include <string.h>



#include "tclsqlite.h"





#ifndef SQLITE_AMALGAMATION
  typedef unsigned char u8;
#endif

typedef struct TestSession TestSession;
struct TestSession {
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
struct TestConflictHandler {
  Tcl_Interp *interp;
  Tcl_Obj *pConflictScript;
  Tcl_Obj *pFilterScript;
};

static int test_obj_eq_string(Tcl_Obj *p, const char *z){
  int n;
  int nObj;
  char *zObj;

  n = (int)strlen(z);
  zObj = Tcl_GetStringFromObj(p, &nObj);

  return (nObj==n && (n==0 || 0==memcmp(zObj, z, n)));
}

static int test_filter_handler(
  void *pCtx,                     /* Pointer to TestConflictHandler structure */







|
|


|







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
struct TestConflictHandler {
  Tcl_Interp *interp;
  Tcl_Obj *pConflictScript;
  Tcl_Obj *pFilterScript;
};

static int test_obj_eq_string(Tcl_Obj *p, const char *z){
  Tcl_Size n;
  Tcl_Size nObj;
  char *zObj;

  n = (Tcl_Size)strlen(z);
  zObj = Tcl_GetStringFromObj(p, &nObj);

  return (nObj==n && (n==0 || 0==memcmp(zObj, z, n)));
}

static int test_filter_handler(
  void *pCtx,                     /* Pointer to TestConflictHandler structure */
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;                    /* Database handle */
  Tcl_CmdInfo info;               /* Database Tcl command (objv[1]) info */
  int rc;                         /* Return code from changeset_invert() */
  void *pChangeset;               /* Buffer containing changeset */
  int nChangeset;                 /* Size of buffer aChangeset in bytes */
  TestConflictHandler ctx;
  TestStreamInput sStr;
  void *pRebase = 0;
  int nRebase = 0;
  int flags = 0;                  /* Flags for apply_v2() */

  memset(&sStr, 0, sizeof(sStr));







|







785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;                    /* Database handle */
  Tcl_CmdInfo info;               /* Database Tcl command (objv[1]) info */
  int rc;                         /* Return code from changeset_invert() */
  void *pChangeset;               /* Buffer containing changeset */
  Tcl_Size nChangeset;            /* Size of buffer aChangeset in bytes */
  TestConflictHandler ctx;
  TestStreamInput sStr;
  void *pRebase = 0;
  int nRebase = 0;
  int flags = 0;                  /* Flags for apply_v2() */

  memset(&sStr, 0, sizeof(sStr));
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[2], &nChangeset);
  ctx.pConflictScript = objv[3];
  ctx.pFilterScript = objc==5 ? objv[4] : 0;
  ctx.interp = interp;

  if( sStr.nStream==0 ){
    if( bV2==0 ){
      rc = sqlite3changeset_apply(db, nChangeset, pChangeset, 
          (objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx
      );
    }else{
      rc = sqlite3changeset_apply_v2(db, nChangeset, pChangeset, 
          (objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx,
          &pRebase, &nRebase, flags
      );
    }
  }else{
    sStr.aData = (unsigned char*)pChangeset;
    sStr.nData = nChangeset;
    if( bV2==0 ){
      rc = sqlite3changeset_apply_strm(db, testStreamInput, (void*)&sStr,
          (objc==5) ? test_filter_handler : 0, 
          test_conflict_handler, (void *)&ctx
      );
    }else{
      rc = sqlite3changeset_apply_v2_strm(db, testStreamInput, (void*)&sStr,







|



|






|







842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[2], &nChangeset);
  ctx.pConflictScript = objv[3];
  ctx.pFilterScript = objc==5 ? objv[4] : 0;
  ctx.interp = interp;

  if( sStr.nStream==0 ){
    if( bV2==0 ){
      rc = sqlite3changeset_apply(db, (int)nChangeset, pChangeset, 
          (objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx
      );
    }else{
      rc = sqlite3changeset_apply_v2(db, (int)nChangeset, pChangeset, 
          (objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx,
          &pRebase, &nRebase, flags
      );
    }
  }else{
    sStr.aData = (unsigned char*)pChangeset;
    sStr.nData = (int)nChangeset;
    if( bV2==0 ){
      rc = sqlite3changeset_apply_strm(db, testStreamInput, (void*)&sStr,
          (objc==5) ? test_filter_handler : 0, 
          test_conflict_handler, (void *)&ctx
      );
    }else{
      rc = sqlite3changeset_apply_v2_strm(db, testStreamInput, (void*)&sStr,
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961

962
963
964
965
966
967
968
969
970
971
972
973

974
975
976
977
978
979
980
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;                    /* Database handle */
  Tcl_CmdInfo info;               /* Database Tcl command (objv[1]) info */
  int rc;                         /* Return code from changeset_invert() */
  void *pChangeset;               /* Buffer containing changeset */
  int nChangeset;                 /* Size of buffer aChangeset in bytes */

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB CHANGESET");
    return TCL_ERROR;
  }
  if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &info) ){
    Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(objv[2]), 0);
    return TCL_ERROR;
  }
  db = *(sqlite3 **)info.objClientData;
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[2], &nChangeset);

  rc = sqlite3changeset_apply(db, nChangeset, pChangeset, 0, replace_handler,0);

  if( rc!=SQLITE_OK ){
    return test_session_error(interp, rc, 0);
  }
  Tcl_ResetResult(interp);
  return TCL_OK;
}


/*
** sqlite3changeset_invert CHANGESET
*/
static int SQLITE_TCLAPI test_sqlite3changeset_invert(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int rc;                         /* Return code from changeset_invert() */

  TestStreamInput sIn;            /* Input stream */
  TestSessionsBlob sOut;          /* Output blob */

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "CHANGESET");
    return TCL_ERROR;
  }

  memset(&sIn, 0, sizeof(sIn));
  memset(&sOut, 0, sizeof(sOut));
  sIn.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
  sIn.aData = Tcl_GetByteArrayFromObj(objv[1], &sIn.nData);


  if( sIn.nStream ){
    rc = sqlite3changeset_invert_strm(
        testStreamInput, (void*)&sIn, testStreamOutput, (void*)&sOut
    );
  }else{
    rc = sqlite3changeset_invert(sIn.nData, sIn.aData, &sOut.n, &sOut.p);







|












|
>


















>











|
>







916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;                    /* Database handle */
  Tcl_CmdInfo info;               /* Database Tcl command (objv[1]) info */
  int rc;                         /* Return code from changeset_invert() */
  void *pChangeset;               /* Buffer containing changeset */
  Tcl_Size nChangeset;            /* Size of buffer aChangeset in bytes */

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB CHANGESET");
    return TCL_ERROR;
  }
  if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &info) ){
    Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(objv[2]), 0);
    return TCL_ERROR;
  }
  db = *(sqlite3 **)info.objClientData;
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[2], &nChangeset);

  rc = sqlite3changeset_apply(db, (int)nChangeset, pChangeset,
                              0, replace_handler,0);
  if( rc!=SQLITE_OK ){
    return test_session_error(interp, rc, 0);
  }
  Tcl_ResetResult(interp);
  return TCL_OK;
}


/*
** sqlite3changeset_invert CHANGESET
*/
static int SQLITE_TCLAPI test_sqlite3changeset_invert(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int rc;                         /* Return code from changeset_invert() */
  Tcl_Size nn;
  TestStreamInput sIn;            /* Input stream */
  TestSessionsBlob sOut;          /* Output blob */

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "CHANGESET");
    return TCL_ERROR;
  }

  memset(&sIn, 0, sizeof(sIn));
  memset(&sOut, 0, sizeof(sOut));
  sIn.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
  sIn.aData = Tcl_GetByteArrayFromObj(objv[1], &nn);
  sIn.nData = (int)nn;

  if( sIn.nStream ){
    rc = sqlite3changeset_invert_strm(
        testStreamInput, (void*)&sIn, testStreamOutput, (void*)&sOut
    );
  }else{
    rc = sqlite3changeset_invert(sIn.nData, sIn.aData, &sOut.n, &sOut.p);
995
996
997
998
999
1000
1001

1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014

1015

1016
1017
1018
1019
1020
1021
1022
static int SQLITE_TCLAPI test_sqlite3changeset_concat(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int rc;                         /* Return code from changeset_invert() */


  TestStreamInput sLeft;          /* Input stream */
  TestStreamInput sRight;         /* Input stream */
  TestSessionsBlob sOut = {0,0};  /* Output blob */

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "LEFT RIGHT");
    return TCL_ERROR;
  }

  memset(&sLeft, 0, sizeof(sLeft));
  memset(&sRight, 0, sizeof(sRight));
  sLeft.aData = Tcl_GetByteArrayFromObj(objv[1], &sLeft.nData);

  sRight.aData = Tcl_GetByteArrayFromObj(objv[2], &sRight.nData);

  sLeft.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
  sRight.nStream = sLeft.nStream;

  if( sLeft.nStream>0 ){
    rc = sqlite3changeset_concat_strm(
        testStreamInput, (void*)&sLeft,
        testStreamInput, (void*)&sRight,







>












|
>
|
>







991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
static int SQLITE_TCLAPI test_sqlite3changeset_concat(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int rc;                         /* Return code from changeset_invert() */
  Tcl_Size nn;

  TestStreamInput sLeft;          /* Input stream */
  TestStreamInput sRight;         /* Input stream */
  TestSessionsBlob sOut = {0,0};  /* Output blob */

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "LEFT RIGHT");
    return TCL_ERROR;
  }

  memset(&sLeft, 0, sizeof(sLeft));
  memset(&sRight, 0, sizeof(sRight));
  sLeft.aData = Tcl_GetByteArrayFromObj(objv[1], &nn);
  sLeft.nData = (int)nn;
  sRight.aData = Tcl_GetByteArrayFromObj(objv[2], &nn);
  sRight.nData = (int)nn;
  sLeft.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
  sRight.nStream = sLeft.nStream;

  if( sLeft.nStream>0 ){
    rc = sqlite3changeset_concat_strm(
        testStreamInput, (void*)&sLeft,
        testStreamInput, (void*)&sRight,
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
static int SQLITE_TCLAPI test_sqlite3session_foreach(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  void *pChangeset;
  int nChangeset;
  sqlite3_changeset_iter *pIter;
  int rc;
  Tcl_Obj *pVarname;
  Tcl_Obj *pCS;
  Tcl_Obj *pScript;
  int isCheckNext = 0;
  int isInvert = 0;







|







1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
static int SQLITE_TCLAPI test_sqlite3session_foreach(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  void *pChangeset;
  Tcl_Size nChangeset;
  sqlite3_changeset_iter *pIter;
  int rc;
  Tcl_Obj *pVarname;
  Tcl_Obj *pCS;
  Tcl_Obj *pScript;
  int isCheckNext = 0;
  int isInvert = 0;
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
  pScript = objv[3];

  pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset);
  sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
  if( isInvert ){
    int f = SQLITE_CHANGESETSTART_INVERT;
    if( sStr.nStream==0 ){
      rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, f);
    }else{
      void *pCtx = (void*)&sStr;
      sStr.aData = (unsigned char*)pChangeset;
      sStr.nData = nChangeset;
      rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f);
    }
  }else{
    if( sStr.nStream==0 ){
      rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
    }else{
      sStr.aData = (unsigned char*)pChangeset;
      sStr.nData = nChangeset;
      rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
    }
  }
  if( rc!=SQLITE_OK ){
    return test_session_error(interp, rc, 0);
  }








|



|




|


|







1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  pScript = objv[3];

  pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset);
  sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
  if( isInvert ){
    int f = SQLITE_CHANGESETSTART_INVERT;
    if( sStr.nStream==0 ){
      rc = sqlite3changeset_start_v2(&pIter, (int)nChangeset, pChangeset, f);
    }else{
      void *pCtx = (void*)&sStr;
      sStr.aData = (unsigned char*)pChangeset;
      sStr.nData = (int)nChangeset;
      rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f);
    }
  }else{
    if( sStr.nStream==0 ){
      rc = sqlite3changeset_start(&pIter, (int)nChangeset, pChangeset);
    }else{
      sStr.aData = (unsigned char*)pChangeset;
      sStr.nData = (int)nChangeset;
      rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
    }
  }
  if( rc!=SQLITE_OK ){
    return test_session_error(interp, rc, 0);
  }

1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252

1253
1254
1255
1256

1257
1258
1259
1260
1261
1262
1263
    return TCL_ERROR;
  }

  assert( iSub==0 || iSub==1 || iSub==2 );
  assert( rc==SQLITE_OK );
  switch( iSub ){
    case 0: {   /* configure */
      int nRebase = 0;
      unsigned char *pRebase = Tcl_GetByteArrayFromObj(objv[2], &nRebase);
      rc = sqlite3rebaser_configure(p, nRebase, pRebase);
      break;
    }

    case 1:     /* delete */
      Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
      break;

    default: {  /* rebase */
      TestStreamInput sStr;                 /* Input stream */
      TestSessionsBlob sOut;                /* Output blob */


      memset(&sStr, 0, sizeof(sStr));
      memset(&sOut, 0, sizeof(sOut));
      sStr.aData = Tcl_GetByteArrayFromObj(objv[2], &sStr.nData);

      sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);

      if( sStr.nStream ){
        rc = sqlite3rebaser_rebase_strm(p, 
            testStreamInput, (void*)&sStr,
            testStreamOutput, (void*)&sOut
        );







|

|










>



|
>







1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
    return TCL_ERROR;
  }

  assert( iSub==0 || iSub==1 || iSub==2 );
  assert( rc==SQLITE_OK );
  switch( iSub ){
    case 0: {   /* configure */
      Tcl_Size nRebase = 0;
      unsigned char *pRebase = Tcl_GetByteArrayFromObj(objv[2], &nRebase);
      rc = sqlite3rebaser_configure(p, (int)nRebase, pRebase);
      break;
    }

    case 1:     /* delete */
      Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
      break;

    default: {  /* rebase */
      TestStreamInput sStr;                 /* Input stream */
      TestSessionsBlob sOut;                /* Output blob */
      Tcl_Size nn;

      memset(&sStr, 0, sizeof(sStr));
      memset(&sOut, 0, sizeof(sOut));
      sStr.aData = Tcl_GetByteArrayFromObj(objv[2], &nn);
      sStr.nData = nn;
      sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);

      if( sStr.nStream ){
        rc = sqlite3rebaser_rebase_strm(p, 
            testStreamInput, (void*)&sStr,
            testStreamOutput, (void*)&sOut
        );
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
static int SQLITE_TCLAPI test_changeset(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  void *pChangeset = 0;           /* Buffer containing changeset */
  int nChangeset = 0;             /* Size of buffer aChangeset in bytes */
  int rc = SQLITE_OK;
  char *z = 0;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "CHANGESET");
    return TCL_ERROR;
  }
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[1], &nChangeset);

  Tcl_ResetResult(interp);
  rc = sqlite3_test_changeset(nChangeset, pChangeset, &z);
  if( rc!=SQLITE_OK ){
    char *zErr = sqlite3_mprintf("(%d) - \"%s\"", rc, z);
    Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
    sqlite3_free(zErr);
  }
  sqlite3_free(z);








|










|







1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
static int SQLITE_TCLAPI test_changeset(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  void *pChangeset = 0;           /* Buffer containing changeset */
  Tcl_Size nChangeset = 0;        /* Size of buffer aChangeset in bytes */
  int rc = SQLITE_OK;
  char *z = 0;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "CHANGESET");
    return TCL_ERROR;
  }
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[1], &nChangeset);

  Tcl_ResetResult(interp);
  rc = sqlite3_test_changeset((int)nChangeset, pChangeset, &z);
  if( rc!=SQLITE_OK ){
    char *zErr = sqlite3_mprintf("(%d) - \"%s\"", rc, z);
    Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
    sqlite3_free(zErr);
  }
  sqlite3_free(z);

1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
      }
      rc = sqlite3changegroup_schema(p->pGrp, db, zDb);
      if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0);
      break;
    };

    case 1: {      /* add */
      int nByte = 0;
      const u8 *aByte = Tcl_GetByteArrayFromObj(objv[2], &nByte);
      rc = sqlite3changegroup_add(p->pGrp, nByte, (void*)aByte);
      if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0);
      break;
    };

    case 2: {      /* output */
      int nByte = 0;
      u8 *aByte = 0;







|

|







1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
      }
      rc = sqlite3changegroup_schema(p->pGrp, db, zDb);
      if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0);
      break;
    };

    case 1: {      /* add */
      Tcl_Size nByte = 0;
      const u8 *aByte = Tcl_GetByteArrayFromObj(objv[2], &nByte);
      rc = sqlite3changegroup_add(p->pGrp, (int)nByte, (void*)aByte);
      if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0);
      break;
    };

    case 2: {      /* output */
      int nByte = 0;
      u8 *aByte = 0;
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int isInvert = 0;
  void *pChangeset = 0;           /* Buffer containing changeset */
  int nChangeset = 0;             /* Size of buffer aChangeset in bytes */
  TestChangeIter *pNew = 0;
  sqlite3_changeset_iter *pIter = 0;
  int flags = 0;
  int rc = SQLITE_OK;

  static int iCmd = 1;
  char zCmd[64];

  if( objc==3 ){
    int n = 0;
    const char *z = Tcl_GetStringFromObj(objv[1], &n);
    isInvert = (n>=2 && sqlite3_strnicmp(z, "-invert", n)==0);
  }

  if( objc!=2 && (objc!=3 || !isInvert) ){
    Tcl_WrongNumArgs(interp, 1, objv, "?-invert? CHANGESET");
    return TCL_ERROR;
  }

  flags = isInvert ? SQLITE_CHANGESETSTART_INVERT : 0;
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[objc-1], &nChangeset);
  rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, flags);
  if( rc!=SQLITE_OK ){
    char *zErr = sqlite3_mprintf(
        "error in sqlite3changeset_start_v2() - %d", rc
    );
    Tcl_AppendResult(interp, zErr, (char*)0);
    return TCL_ERROR;
  }







|









|

|









|







1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int isInvert = 0;
  void *pChangeset = 0;           /* Buffer containing changeset */
  Tcl_Size nChangeset = 0;        /* Size of buffer aChangeset in bytes */
  TestChangeIter *pNew = 0;
  sqlite3_changeset_iter *pIter = 0;
  int flags = 0;
  int rc = SQLITE_OK;

  static int iCmd = 1;
  char zCmd[64];

  if( objc==3 ){
    Tcl_Size n = 0;
    const char *z = Tcl_GetStringFromObj(objv[1], &n);
    isInvert = (n>=2 && sqlite3_strnicmp(z, "-invert", (int)n)==0);
  }

  if( objc!=2 && (objc!=3 || !isInvert) ){
    Tcl_WrongNumArgs(interp, 1, objv, "?-invert? CHANGESET");
    return TCL_ERROR;
  }

  flags = isInvert ? SQLITE_CHANGESETSTART_INVERT : 0;
  pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[objc-1], &nChangeset);
  rc = sqlite3changeset_start_v2(&pIter, (int)nChangeset, pChangeset, flags);
  if( rc!=SQLITE_OK ){
    char *zErr = sqlite3_mprintf(
        "error in sqlite3changeset_start_v2() - %d", rc
    );
    Tcl_AppendResult(interp, zErr, (char*)0);
    return TCL_ERROR;
  }
Changes to src/alter.c.
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
  pParse->pTriggerTab = sqlite3FindTable(db, pNew->table,
      db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
  );
  pParse->eTriggerOp = pNew->op;
  /* ALWAYS() because if the table of the trigger does not exist, the
  ** error would have been hit before this point */
  if( ALWAYS(pParse->pTriggerTab) ){
    rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
  }

  /* Resolve symbols in WHEN clause */
  if( rc==SQLITE_OK && pNew->pWhen ){
    rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen);
  }








|







1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
  pParse->pTriggerTab = sqlite3FindTable(db, pNew->table,
      db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
  );
  pParse->eTriggerOp = pNew->op;
  /* ALWAYS() because if the table of the trigger does not exist, the
  ** error would have been hit before this point */
  if( ALWAYS(pParse->pTriggerTab) ){
    rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0;
  }

  /* Resolve symbols in WHEN clause */
  if( rc==SQLITE_OK && pNew->pWhen ){
    rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen);
  }

Changes to src/insert.c.
713
714
715
716
717
718
719

720
721
722
723
724
725
726
      }

      if( pRet ){
        SelectDest dest;
        pRet->pSrc->nSrc = 1;
        pRet->pPrior = pLeft->pPrior;
        pRet->op = pLeft->op;

        pLeft->pPrior = 0;
        pLeft->op = TK_SELECT;
        assert( pLeft->pNext==0 );
        assert( pRet->pNext==0 );
        p = &pRet->pSrc->a[0];
        p->pSelect = pLeft;
        p->fg.viaCoroutine = 1;







>







713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
      }

      if( pRet ){
        SelectDest dest;
        pRet->pSrc->nSrc = 1;
        pRet->pPrior = pLeft->pPrior;
        pRet->op = pLeft->op;
        if( pRet->pPrior ) pRet->selFlags |= SF_Values;
        pLeft->pPrior = 0;
        pLeft->op = TK_SELECT;
        assert( pLeft->pNext==0 );
        assert( pRet->pNext==0 );
        p = &pRet->pSrc->a[0];
        p->pSelect = pLeft;
        p->fg.viaCoroutine = 1;
Changes to src/parse.y.
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
        if( pLoop->pOrderBy || pLoop->pLimit ){
          sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
             pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT",
             sqlite3SelectOpName(pNext->op));
          break;
        }
      }
      if( (p->selFlags & SF_MultiValue)==0 && 
        (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
        cnt>mxSelect
      ){
        sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
      }
    }
  }

  /* Attach a With object describing the WITH clause to a Select







|
|
|







528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
        if( pLoop->pOrderBy || pLoop->pLimit ){
          sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
             pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT",
             sqlite3SelectOpName(pNext->op));
          break;
        }
      }
      if( (p->selFlags & (SF_MultiValue|SF_Values))==0
       && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
       && cnt>mxSelect
      ){
        sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
      }
    }
  }

  /* Attach a With object describing the WITH clause to a Select
Changes to src/resolve.c.
2150
2151
2152
2153
2154
2155
2156



2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
  return pNC->nNcErr>0 || w.pParse->nErr>0;
}

/*
** Resolve all names for all expression in an expression list.  This is
** just like sqlite3ResolveExprNames() except that it works for an expression
** list rather than a single expression.



*/
int sqlite3ResolveExprListNames(
  NameContext *pNC,       /* Namespace to resolve expressions in. */
  ExprList *pList         /* The expression list to be analyzed. */
){
  int i;
  int savedHasAgg = 0;
  Walker w;
  if( pList==0 ) return WRC_Continue;
  w.pParse = pNC->pParse;
  w.xExprCallback = resolveExprStep;
  w.xSelectCallback = resolveSelectStep;
  w.xSelectCallback2 = 0;
  w.u.pNC = pNC;
  savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
  pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
  for(i=0; i<pList->nExpr; i++){
    Expr *pExpr = pList->a[i].pExpr;
    if( pExpr==0 ) continue;
#if SQLITE_MAX_EXPR_DEPTH>0
    w.pParse->nHeight += pExpr->nHeight;
    if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
      return WRC_Abort;
    }
#endif
    sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
    w.pParse->nHeight -= pExpr->nHeight;
#endif
    assert( EP_Agg==NC_HasAgg );
    assert( EP_Win==NC_HasWin );
    testcase( pNC->ncFlags & NC_HasAgg );
    testcase( pNC->ncFlags & NC_HasWin );
    if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg) ){
      ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) );
      savedHasAgg |= pNC->ncFlags &
                          (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
      pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
    }
    if( w.pParse->nErr>0 ) return WRC_Abort;
  }
  pNC->ncFlags |= savedHasAgg;
  return WRC_Continue;
}

/*
** Resolve all names in all expressions of a SELECT and in all
** descendants of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause
** terms.







>
>
>








|













|
















|


|







2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
  return pNC->nNcErr>0 || w.pParse->nErr>0;
}

/*
** Resolve all names for all expression in an expression list.  This is
** just like sqlite3ResolveExprNames() except that it works for an expression
** list rather than a single expression.
**
** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a
** failure.
*/
int sqlite3ResolveExprListNames(
  NameContext *pNC,       /* Namespace to resolve expressions in. */
  ExprList *pList         /* The expression list to be analyzed. */
){
  int i;
  int savedHasAgg = 0;
  Walker w;
  if( pList==0 ) return SQLITE_OK;
  w.pParse = pNC->pParse;
  w.xExprCallback = resolveExprStep;
  w.xSelectCallback = resolveSelectStep;
  w.xSelectCallback2 = 0;
  w.u.pNC = pNC;
  savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
  pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
  for(i=0; i<pList->nExpr; i++){
    Expr *pExpr = pList->a[i].pExpr;
    if( pExpr==0 ) continue;
#if SQLITE_MAX_EXPR_DEPTH>0
    w.pParse->nHeight += pExpr->nHeight;
    if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
      return SQLITE_ERROR;
    }
#endif
    sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
    w.pParse->nHeight -= pExpr->nHeight;
#endif
    assert( EP_Agg==NC_HasAgg );
    assert( EP_Win==NC_HasWin );
    testcase( pNC->ncFlags & NC_HasAgg );
    testcase( pNC->ncFlags & NC_HasWin );
    if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg) ){
      ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) );
      savedHasAgg |= pNC->ncFlags &
                          (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
      pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
    }
    if( w.pParse->nErr>0 ) return SQLITE_ERROR;
  }
  pNC->ncFlags |= savedHasAgg;
  return SQLITE_OK;
}

/*
** Resolve all names in all expressions of a SELECT and in all
** descendants of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause
** terms.
Changes to src/shell.c.in.
3541
3542
3543
3544
3545
3546
3547








3548
3549
3550
3551
3552
3553
3554
    }else if( sqlite3_strlike("_NAN", zVar, 0)==0 ){
      sqlite3_bind_double(pStmt, i, NAN);
#endif
#ifdef INFINITY
    }else if( sqlite3_strlike("_INF", zVar, 0)==0 ){
      sqlite3_bind_double(pStmt, i, INFINITY);
#endif








    }else{
      sqlite3_bind_null(pStmt, i);
    }
    sqlite3_reset(pQ);
  }
  sqlite3_finalize(pQ);
}







>
>
>
>
>
>
>
>







3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
    }else if( sqlite3_strlike("_NAN", zVar, 0)==0 ){
      sqlite3_bind_double(pStmt, i, NAN);
#endif
#ifdef INFINITY
    }else if( sqlite3_strlike("_INF", zVar, 0)==0 ){
      sqlite3_bind_double(pStmt, i, INFINITY);
#endif
    }else if( strncmp(zVar, "$int_", 5)==0 ){
      sqlite3_bind_int(pStmt, i, atoi(&zVar[5]));
    }else if( strncmp(zVar, "$text_", 6)==0 ){
      char *zBuf = sqlite3_malloc64( strlen(zVar)-5 );
      if( zBuf ){
        memcpy(zBuf, &zVar[6], strlen(zVar)-5);
        sqlite3_bind_text64(pStmt, i, zBuf, -1, sqlite3_free, SQLITE_UTF8);
      }
    }else{
      sqlite3_bind_null(pStmt, i);
    }
    sqlite3_reset(pQ);
  }
  sqlite3_finalize(pQ);
}
11636
11637
11638
11639
11640
11641
11642
11643



11644
11645
11646
11647
11648
11649
11650
  int rc = SQLITE_OK;

  if( p->eRestoreState<7 ){
    switch( p->eRestoreState ){
      case 0: {
        const char *zExpect = "PRAGMA foreign_keys=OFF;";
        assert( strlen(zExpect)==24 );
        if( p->bSafeMode==0 && memcmp(zSql, zExpect, 25)==0 ){



          p->eRestoreState = 1;
        }else{
          p->eRestoreState = 7;
        }
        break;
      };
  







|
>
>
>







11644
11645
11646
11647
11648
11649
11650
11651
11652
11653
11654
11655
11656
11657
11658
11659
11660
11661
  int rc = SQLITE_OK;

  if( p->eRestoreState<7 ){
    switch( p->eRestoreState ){
      case 0: {
        const char *zExpect = "PRAGMA foreign_keys=OFF;";
        assert( strlen(zExpect)==24 );
        if( p->bSafeMode==0
         && strlen(zSql)>=24
         && memcmp(zSql, zExpect, 25)==0
        ){
          p->eRestoreState = 1;
        }else{
          p->eRestoreState = 7;
        }
        break;
      };
  
Changes to src/sqliteInt.h.
2910
2911
2912
2913
2914
2915
2916

2917
2918
2919





2920
2921
2922
2923
2924
2925
2926
/*
** Macros to compute aCol[] and aFunc[] register numbers.
**
** These macros should not be used prior to the call to
** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg.
** The assert()s that are part of this macro verify that constraint.
*/

#define AggInfoColumnReg(A,I)  (assert((A)->iFirstReg),(A)->iFirstReg+(I))
#define AggInfoFuncReg(A,I)    \
                      (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I))






/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits.  But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit.  16-bit is preferred because
** it uses less memory in the Expr object, which is a big memory user
** in systems with lots of prepared statements.  And few applications







>



>
>
>
>
>







2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
/*
** Macros to compute aCol[] and aFunc[] register numbers.
**
** These macros should not be used prior to the call to
** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg.
** The assert()s that are part of this macro verify that constraint.
*/
#ifndef NDEBUG
#define AggInfoColumnReg(A,I)  (assert((A)->iFirstReg),(A)->iFirstReg+(I))
#define AggInfoFuncReg(A,I)    \
                      (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I))
#else
#define AggInfoColumnReg(A,I)  ((A)->iFirstReg+(I))
#define AggInfoFuncReg(A,I)    \
                      ((A)->iFirstReg+(A)->nColumn+(I))
#endif

/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits.  But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit.  16-bit is preferred because
** it uses less memory in the Expr object, which is a big memory user
** in systems with lots of prepared statements.  And few applications
Changes to src/tclsqlite.c.
31
32
33
34
35
36
37

38
39
40
41
42
43
44
45








46
47
48
49
50
51
52
/*
** If requested, include the SQLite compiler options file for MSVC.
*/
#if defined(INCLUDE_MSVC_H)
# include "msvc.h"
#endif


#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
#  define SQLITE_TCLAPI
# endif
#endif








#include <errno.h>

/*
** Some additional include files are needed if this file is not
** appended to the amalgamation.
*/
#ifndef SQLITE_AMALGAMATION







>

|

|

|


>
>
>
>
>
>
>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
** If requested, include the SQLite compiler options file for MSVC.
*/
#if defined(INCLUDE_MSVC_H)
# include "msvc.h"
#endif

/****** Copy of tclsqlite.h ******/
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"   /* Special case for Windows using STDCALL */
#else
# include <tcl.h>          /* All normal cases */
# ifndef SQLITE_TCLAPI
#   define SQLITE_TCLAPI
# endif
#endif
/* Compatability between Tcl8.6 and Tcl9.0 */
#if TCL_MAJOR_VERSION==9
# define CONST const
#else
  typedef int Tcl_Size;
#endif
/**** End copy of tclsqlite.h ****/

#include <errno.h>

/*
** Some additional include files are needed if this file is not
** appended to the amalgamation.
*/
#ifndef SQLITE_AMALGAMATION
205
206
207
208
209
210
211
212

213
214
215
216
217
218
219
  int bLegacyPrepare;        /* True to use sqlite3_prepare() */
#endif
};

struct IncrblobChannel {
  sqlite3_blob *pBlob;      /* sqlite3 blob handle */
  SqliteDb *pDb;            /* Associated database connection */
  int iSeek;                /* Current seek offset */

  Tcl_Channel channel;      /* Channel identifier */
  IncrblobChannel *pNext;   /* Linked list of all open incrblob channels */
  IncrblobChannel *pPrev;   /* Linked list of all open incrblob channels */
};

/*
** Compute a string length that is limited to what can be stored in







|
>







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  int bLegacyPrepare;        /* True to use sqlite3_prepare() */
#endif
};

struct IncrblobChannel {
  sqlite3_blob *pBlob;      /* sqlite3 blob handle */
  SqliteDb *pDb;            /* Associated database connection */
  sqlite3_int64 iSeek;      /* Current seek offset */
  unsigned int isClosed;    /* TCL_CLOSE_READ or TCL_CLOSE_WRITE */
  Tcl_Channel channel;      /* Channel identifier */
  IncrblobChannel *pNext;   /* Linked list of all open incrblob channels */
  IncrblobChannel *pPrev;   /* Linked list of all open incrblob channels */
};

/*
** Compute a string length that is limited to what can be stored in
245
246
247
248
249
250
251
252
253
254

255
256
257
258
259








260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279







280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345







346
347
348
349
350
351
352
353
354
355
356
357
358
    Tcl_UnregisterChannel(pDb->interp, p->channel);
  }
}

/*
** Close an incremental blob channel.
*/
static int SQLITE_TCLAPI incrblobClose(
  ClientData instanceData,
  Tcl_Interp *interp

){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;
  int rc = sqlite3_blob_close(p->pBlob);
  sqlite3 *db = p->pDb->db;









  /* Remove the channel from the SqliteDb.pIncrblob list. */
  if( p->pNext ){
    p->pNext->pPrev = p->pPrev;
  }
  if( p->pPrev ){
    p->pPrev->pNext = p->pNext;
  }
  if( p->pDb->pIncrblob==p ){
    p->pDb->pIncrblob = p->pNext;
  }

  /* Free the IncrblobChannel structure */
  Tcl_Free((char *)p);

  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
    return TCL_ERROR;
  }
  return TCL_OK;
}








/*
** Read data from an incremental blob channel.
*/
static int SQLITE_TCLAPI incrblobInput(
  ClientData instanceData,
  char *buf,
  int bufSize,
  int *errorCodePtr
){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;
  int nRead = bufSize;         /* Number of bytes to read */
  int nBlob;                   /* Total size of the blob */
  int rc;                      /* sqlite error code */

  nBlob = sqlite3_blob_bytes(p->pBlob);
  if( (p->iSeek+nRead)>nBlob ){
    nRead = nBlob-p->iSeek;
  }
  if( nRead<=0 ){
    return 0;
  }

  rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek);
  if( rc!=SQLITE_OK ){
    *errorCodePtr = rc;
    return -1;
  }

  p->iSeek += nRead;
  return nRead;
}

/*
** Write data to an incremental blob channel.
*/
static int SQLITE_TCLAPI incrblobOutput(
  ClientData instanceData,
  CONST char *buf,
  int toWrite,
  int *errorCodePtr
){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;
  int nWrite = toWrite;        /* Number of bytes to write */
  int nBlob;                   /* Total size of the blob */
  int rc;                      /* sqlite error code */

  nBlob = sqlite3_blob_bytes(p->pBlob);
  if( (p->iSeek+nWrite)>nBlob ){
    *errorCodePtr = EINVAL;
    return -1;
  }
  if( nWrite<=0 ){
    return 0;
  }

  rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek);
  if( rc!=SQLITE_OK ){
    *errorCodePtr = EIO;
    return -1;
  }

  p->iSeek += nWrite;
  return nWrite;
}








/*
** Seek an incremental blob channel.
*/
static int SQLITE_TCLAPI incrblobSeek(
  ClientData instanceData,
  long offset,
  int seekMode,
  int *errorCodePtr
){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;

  switch( seekMode ){
    case SEEK_SET:







|

|
>


|


>
>
>
>
>
>
>
>




















>
>
>
>
>
>
>











|
|
|









|



















|
|
|










|









>
>
>
>
>
>
>



|

|







255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
    Tcl_UnregisterChannel(pDb->interp, p->channel);
  }
}

/*
** Close an incremental blob channel.
*/
static int SQLITE_TCLAPI incrblobClose2(
  ClientData instanceData,
  Tcl_Interp *interp,
  int flags
){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;
  int  rc;
  sqlite3 *db = p->pDb->db;

  if( flags ){
    p->isClosed |= flags;
    return TCL_OK;
  }

  /* If we reach this point, then we really do need to close the channel */
  rc = sqlite3_blob_close(p->pBlob);

  /* Remove the channel from the SqliteDb.pIncrblob list. */
  if( p->pNext ){
    p->pNext->pPrev = p->pPrev;
  }
  if( p->pPrev ){
    p->pPrev->pNext = p->pNext;
  }
  if( p->pDb->pIncrblob==p ){
    p->pDb->pIncrblob = p->pNext;
  }

  /* Free the IncrblobChannel structure */
  Tcl_Free((char *)p);

  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
    return TCL_ERROR;
  }
  return TCL_OK;
}
static int SQLITE_TCLAPI incrblobClose(
  ClientData instanceData,
  Tcl_Interp *interp
){
  return incrblobClose2(instanceData, interp, 0);
}


/*
** Read data from an incremental blob channel.
*/
static int SQLITE_TCLAPI incrblobInput(
  ClientData instanceData,
  char *buf,
  int bufSize,
  int *errorCodePtr
){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;
  sqlite3_int64 nRead = bufSize;   /* Number of bytes to read */
  sqlite3_int64 nBlob;             /* Total size of the blob */
  int rc;                          /* sqlite error code */

  nBlob = sqlite3_blob_bytes(p->pBlob);
  if( (p->iSeek+nRead)>nBlob ){
    nRead = nBlob-p->iSeek;
  }
  if( nRead<=0 ){
    return 0;
  }

  rc = sqlite3_blob_read(p->pBlob, (void *)buf, (int)nRead, (int)p->iSeek);
  if( rc!=SQLITE_OK ){
    *errorCodePtr = rc;
    return -1;
  }

  p->iSeek += nRead;
  return nRead;
}

/*
** Write data to an incremental blob channel.
*/
static int SQLITE_TCLAPI incrblobOutput(
  ClientData instanceData,
  CONST char *buf,
  int toWrite,
  int *errorCodePtr
){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;
  sqlite3_int64 nWrite = toWrite;   /* Number of bytes to write */
  sqlite3_int64 nBlob;              /* Total size of the blob */
  int rc;                           /* sqlite error code */

  nBlob = sqlite3_blob_bytes(p->pBlob);
  if( (p->iSeek+nWrite)>nBlob ){
    *errorCodePtr = EINVAL;
    return -1;
  }
  if( nWrite<=0 ){
    return 0;
  }

  rc = sqlite3_blob_write(p->pBlob, (void*)buf,(int)nWrite, (int)p->iSeek);
  if( rc!=SQLITE_OK ){
    *errorCodePtr = EIO;
    return -1;
  }

  p->iSeek += nWrite;
  return nWrite;
}

/* The datatype of Tcl_DriverWideSeekProc changes between tcl8.6 and tcl9.0 */
#if TCL_MAJOR_VERSION==9
# define WideSeekProcType long long
#else
# define WideSeekProcType Tcl_WideInt
#endif

/*
** Seek an incremental blob channel.
*/
static WideSeekProcType SQLITE_TCLAPI incrblobWideSeek(
  ClientData instanceData,
  WideSeekProcType offset,
  int seekMode,
  int *errorCodePtr
){
  IncrblobChannel *p = (IncrblobChannel *)instanceData;

  switch( seekMode ){
    case SEEK_SET:
366
367
368
369
370
371
372








373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
      break;

    default: assert(!"Bad seekMode");
  }

  return p->iSeek;
}










static void SQLITE_TCLAPI incrblobWatch(
  ClientData instanceData,
  int mode
){
  /* NO-OP */
}
static int SQLITE_TCLAPI incrblobHandle(
  ClientData instanceData,
  int dir,
  ClientData *hPtr
){
  return TCL_ERROR;
}

static Tcl_ChannelType IncrblobChannelType = {
  "incrblob",                        /* typeName                             */
  TCL_CHANNEL_VERSION_2,             /* version                              */
  incrblobClose,                     /* closeProc                            */
  incrblobInput,                     /* inputProc                            */
  incrblobOutput,                    /* outputProc                           */
  incrblobSeek,                      /* seekProc                             */
  0,                                 /* setOptionProc                        */
  0,                                 /* getOptionProc                        */
  incrblobWatch,                     /* watchProc (this is a no-op)          */
  incrblobHandle,                    /* getHandleProc (always returns error) */
  0,                                 /* close2Proc                           */
  0,                                 /* blockModeProc                        */
  0,                                 /* flushProc                            */
  0,                                 /* handlerProc                          */
  0,                                 /* wideSeekProc                         */
};

/*
** Create a new incrblob channel.
*/
static int createIncrblobChannel(
  Tcl_Interp *interp,







>
>
>
>
>
>
>
>


















|








|



|







399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
      break;

    default: assert(!"Bad seekMode");
  }

  return p->iSeek;
}
static int SQLITE_TCLAPI incrblobSeek(
  ClientData instanceData,
  long offset,
  int seekMode,
  int *errorCodePtr
){
  return incrblobWideSeek(instanceData,offset,seekMode,errorCodePtr);
}


static void SQLITE_TCLAPI incrblobWatch(
  ClientData instanceData,
  int mode
){
  /* NO-OP */
}
static int SQLITE_TCLAPI incrblobHandle(
  ClientData instanceData,
  int dir,
  ClientData *hPtr
){
  return TCL_ERROR;
}

static Tcl_ChannelType IncrblobChannelType = {
  "incrblob",                        /* typeName                             */
  TCL_CHANNEL_VERSION_5,             /* version                              */
  incrblobClose,                     /* closeProc                            */
  incrblobInput,                     /* inputProc                            */
  incrblobOutput,                    /* outputProc                           */
  incrblobSeek,                      /* seekProc                             */
  0,                                 /* setOptionProc                        */
  0,                                 /* getOptionProc                        */
  incrblobWatch,                     /* watchProc (this is a no-op)          */
  incrblobHandle,                    /* getHandleProc (always returns error) */
  incrblobClose2,                    /* close2Proc                           */
  0,                                 /* blockModeProc                        */
  0,                                 /* flushProc                            */
  0,                                 /* handlerProc                          */
  incrblobWideSeek,                  /* wideSeekProc                         */
};

/*
** Create a new incrblob channel.
*/
static int createIncrblobChannel(
  Tcl_Interp *interp,
429
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
  rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob);
  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
    return TCL_ERROR;
  }

  p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));
  p->iSeek = 0;
  p->pBlob = pBlob;


  sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);
  p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);
  Tcl_RegisterChannel(interp, p->channel);

  /* Link the new channel into the SqliteDb.pIncrblob list. */
  p->pNext = pDb->pIncrblob;







|

>







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob);
  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
    return TCL_ERROR;
  }

  p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));
  memset(p, 0, sizeof(*p));
  p->pBlob = pBlob;
  if( (flags & TCL_WRITABLE)==0 ) p->isClosed |= TCL_CLOSE_WRITE;

  sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);
  p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);
  Tcl_RegisterChannel(interp, p->channel);

  /* Link the new channel into the SqliteDb.pIncrblob list. */
  p->pNext = pDb->pIncrblob;
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
*/
static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
  /* We could try to do something with Tcl_Parse().  But we will instead
  ** just do a search for forbidden characters.  If any of the forbidden
  ** characters appear in pCmd, we will report the string as unsafe.
  */
  const char *z;
  int n;
  z = Tcl_GetStringFromObj(pCmd, &n);
  while( n-- > 0 ){
    int c = *(z++);
    if( c=='$' || c=='[' || c==';' ) return 0;
  }
  return 1;
}







|







512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
*/
static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
  /* We could try to do something with Tcl_Parse().  But we will instead
  ** just do a search for forbidden characters.  If any of the forbidden
  ** characters appear in pCmd, we will report the string as unsafe.
  */
  const char *z;
  Tcl_Size n;
  z = Tcl_GetStringFromObj(pCmd, &n);
  while( n-- > 0 ){
    int c = *(z++);
    if( c=='$' || c=='[' || c==';' ) return 0;
  }
  return 1;
}
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
    ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
    ** The new Tcl_Obj contains pointers to the original list elements.
    ** That way, when Tcl_EvalObjv() is run and shimmers the first element
    ** of the list to tclCmdNameType, that alternate representation will
    ** be preserved and reused on the next invocation.
    */
    Tcl_Obj **aArg;
    int nArg;
    if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
      sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
      return;
    }
    pCmd = Tcl_NewListObj(nArg, aArg);
    Tcl_IncrRefCount(pCmd);
    for(i=0; i<argc; i++){







|







1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
    ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
    ** The new Tcl_Obj contains pointers to the original list elements.
    ** That way, when Tcl_EvalObjv() is run and shimmers the first element
    ** of the list to tclCmdNameType, that alternate representation will
    ** be preserved and reused on the next invocation.
    */
    Tcl_Obj **aArg;
    Tcl_Size nArg;
    if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
      sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
      return;
    }
    pCmd = Tcl_NewListObj(nArg, aArg);
    Tcl_IncrRefCount(pCmd);
    for(i=0; i<argc; i++){
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
    Tcl_DecrRefCount(pCmd);
  }

  if( rc && rc!=TCL_RETURN ){
    sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
  }else{
    Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
    int n;
    u8 *data;
    const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
    char c = zType[0];
    int eType = p->eType;

    if( eType==SQLITE_NULL ){
      if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){







|







1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
    Tcl_DecrRefCount(pCmd);
  }

  if( rc && rc!=TCL_RETURN ){
    sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
  }else{
    Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
    Tcl_Size n;
    u8 *data;
    const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
    char c = zType[0];
    int eType = p->eType;

    if( eType==SQLITE_NULL ){
      if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471

1472
1473
1474
1475
1476
1477
1478
1479
1480
          rc = TCL_ERROR;
          break;
        }else{
          pVar = 0;
        }
      }
      if( pVar ){
        int n;
        u8 *data;
        const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
        c = zType[0];
        if( zVar[0]=='@' ||
           (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){
          /* Load a BLOB type if the Tcl variable is a bytearray and
          ** it has no string representation or the host
          ** parameter name begins with "@". */
          data = Tcl_GetByteArrayFromObj(pVar, &n);
          sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
          Tcl_IncrRefCount(pVar);
          pPreStmt->apParm[iParm++] = pVar;
        }else if( c=='b' && strcmp(zType,"boolean")==0 ){

          Tcl_GetIntFromObj(interp, pVar, &n);
          sqlite3_bind_int(pStmt, i, n);
        }else if( c=='d' && strcmp(zType,"double")==0 ){
          double r;
          Tcl_GetDoubleFromObj(interp, pVar, &r);
          sqlite3_bind_double(pStmt, i, r);
        }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
              (c=='i' && strcmp(zType,"int")==0) ){
          Tcl_WideInt v;







|













>
|
|







1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
          rc = TCL_ERROR;
          break;
        }else{
          pVar = 0;
        }
      }
      if( pVar ){
        Tcl_Size n;
        u8 *data;
        const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
        c = zType[0];
        if( zVar[0]=='@' ||
           (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){
          /* Load a BLOB type if the Tcl variable is a bytearray and
          ** it has no string representation or the host
          ** parameter name begins with "@". */
          data = Tcl_GetByteArrayFromObj(pVar, &n);
          sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
          Tcl_IncrRefCount(pVar);
          pPreStmt->apParm[iParm++] = pVar;
        }else if( c=='b' && strcmp(zType,"boolean")==0 ){
          int nn;
          Tcl_GetIntFromObj(interp, pVar, &nn);
          sqlite3_bind_int(pStmt, i, nn);
        }else if( c=='d' && strcmp(zType,"double")==0 ){
          double r;
          Tcl_GetDoubleFromObj(interp, pVar, &r);
          sqlite3_bind_double(pStmt, i, r);
        }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
              (c=='i' && strcmp(zType,"int")==0) ){
          Tcl_WideInt v;
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zAuth ){
        Tcl_AppendResult(interp, pDb->zAuth, (char*)0);
      }
    }else{
      char *zAuth;
      int len;
      if( pDb->zAuth ){
        Tcl_Free(pDb->zAuth);
      }
      zAuth = Tcl_GetStringFromObj(objv[2], &len);
      if( zAuth && len>0 ){
        pDb->zAuth = Tcl_Alloc( len + 1 );
        memcpy(pDb->zAuth, zAuth, len+1);







|







2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zAuth ){
        Tcl_AppendResult(interp, pDb->zAuth, (char*)0);
      }
    }else{
      char *zAuth;
      Tcl_Size len;
      if( pDb->zAuth ){
        Tcl_Free(pDb->zAuth);
      }
      zAuth = Tcl_GetStringFromObj(objv[2], &len);
      if( zAuth && len>0 ){
        pDb->zAuth = Tcl_Alloc( len + 1 );
        memcpy(pDb->zAuth, zAuth, len+1);
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zBindFallback ){
        Tcl_AppendResult(interp, pDb->zBindFallback, (char*)0);
      }
    }else{
      char *zCallback;
      int len;
      if( pDb->zBindFallback ){
        Tcl_Free(pDb->zBindFallback);
      }
      zCallback = Tcl_GetStringFromObj(objv[2], &len);
      if( zCallback && len>0 ){
        pDb->zBindFallback = Tcl_Alloc( len + 1 );
        memcpy(pDb->zBindFallback, zCallback, len+1);







|







2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zBindFallback ){
        Tcl_AppendResult(interp, pDb->zBindFallback, (char*)0);
      }
    }else{
      char *zCallback;
      Tcl_Size len;
      if( pDb->zBindFallback ){
        Tcl_Free(pDb->zBindFallback);
      }
      zCallback = Tcl_GetStringFromObj(objv[2], &len);
      if( zCallback && len>0 ){
        pDb->zBindFallback = Tcl_Alloc( len + 1 );
        memcpy(pDb->zBindFallback, zCallback, len+1);
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zBusy ){
        Tcl_AppendResult(interp, pDb->zBusy, (char*)0);
      }
    }else{
      char *zBusy;
      int len;
      if( pDb->zBusy ){
        Tcl_Free(pDb->zBusy);
      }
      zBusy = Tcl_GetStringFromObj(objv[2], &len);
      if( zBusy && len>0 ){
        pDb->zBusy = Tcl_Alloc( len + 1 );
        memcpy(pDb->zBusy, zBusy, len+1);







|







2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zBusy ){
        Tcl_AppendResult(interp, pDb->zBusy, (char*)0);
      }
    }else{
      char *zBusy;
      Tcl_Size len;
      if( pDb->zBusy ){
        Tcl_Free(pDb->zBusy);
      }
      zBusy = Tcl_GetStringFromObj(objv[2], &len);
      if( zBusy && len>0 ){
        pDb->zBusy = Tcl_Alloc( len + 1 );
        memcpy(pDb->zBusy, zBusy, len+1);
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
  ** Create a new SQL collation function called NAME.  Whenever
  ** that function is called, invoke SCRIPT to evaluate the function.
  */
  case DB_COLLATE: {
    SqlCollate *pCollate;
    char *zName;
    char *zScript;
    int nScript;
    if( objc!=4 ){
      Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
      return TCL_ERROR;
    }
    zName = Tcl_GetStringFromObj(objv[2], 0);
    zScript = Tcl_GetStringFromObj(objv[3], &nScript);
    pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );







|







2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
  ** Create a new SQL collation function called NAME.  Whenever
  ** that function is called, invoke SCRIPT to evaluate the function.
  */
  case DB_COLLATE: {
    SqlCollate *pCollate;
    char *zName;
    char *zScript;
    Tcl_Size nScript;
    if( objc!=4 ){
      Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
      return TCL_ERROR;
    }
    zName = Tcl_GetStringFromObj(objv[2], 0);
    zScript = Tcl_GetStringFromObj(objv[3], &nScript);
    pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zCommit ){
        Tcl_AppendResult(interp, pDb->zCommit, (char*)0);
      }
    }else{
      const char *zCommit;
      int len;
      if( pDb->zCommit ){
        Tcl_Free(pDb->zCommit);
      }
      zCommit = Tcl_GetStringFromObj(objv[2], &len);
      if( zCommit && len>0 ){
        pDb->zCommit = Tcl_Alloc( len + 1 );
        memcpy(pDb->zCommit, zCommit, len+1);







|







2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zCommit ){
        Tcl_AppendResult(interp, pDb->zCommit, (char*)0);
      }
    }else{
      const char *zCommit;
      Tcl_Size len;
      if( pDb->zCommit ){
        Tcl_Free(pDb->zCommit);
      }
      zCommit = Tcl_GetStringFromObj(objv[2], &len);
      if( zCommit && len>0 ){
        pDb->zCommit = Tcl_Alloc( len + 1 );
        memcpy(pDb->zCommit, zCommit, len+1);
2649
2650
2651
2652
2653
2654
2655

2656
2657
2658
2659
2660
2661
2662
2663
                     (char*)0);
    rc = TCL_ERROR;
#else
    const char *zSchema = 0;
    Tcl_Obj *pValue = 0;
    unsigned char *pBA;
    unsigned char *pData;

    int len, xrc;
    sqlite3_int64 mxSize = 0;
    int i;
    int isReadonly = 0;


    if( objc<3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE");







>
|







2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
                     (char*)0);
    rc = TCL_ERROR;
#else
    const char *zSchema = 0;
    Tcl_Obj *pValue = 0;
    unsigned char *pBA;
    unsigned char *pData;
    Tcl_Size len;
    int xrc;
    sqlite3_int64 mxSize = 0;
    int i;
    int isReadonly = 0;


    if( objc<3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE");
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
  */
  case DB_NULLVALUE: {
    if( objc!=2 && objc!=3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
      return TCL_ERROR;
    }
    if( objc==3 ){
      int len;
      char *zNull = Tcl_GetStringFromObj(objv[2], &len);
      if( pDb->zNull ){
        Tcl_Free(pDb->zNull);
      }
      if( zNull && len>0 ){
        pDb->zNull = Tcl_Alloc( len + 1 );
        memcpy(pDb->zNull, zNull, len);







|







3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
  */
  case DB_NULLVALUE: {
    if( objc!=2 && objc!=3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
      return TCL_ERROR;
    }
    if( objc==3 ){
      Tcl_Size len;
      char *zNull = Tcl_GetStringFromObj(objv[2], &len);
      if( pDb->zNull ){
        Tcl_Free(pDb->zNull);
      }
      if( zNull && len>0 ){
        pDb->zNull = Tcl_Alloc( len + 1 );
        memcpy(pDb->zNull, zNull, len);
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
        Tcl_AppendResult(interp, pDb->zProgress, (char*)0);
      }
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
      sqlite3_progress_handler(pDb->db, 0, 0, 0);
#endif
    }else if( objc==4 ){
      char *zProgress;
      int len;
      int N;
      if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
        return TCL_ERROR;
      };
      if( pDb->zProgress ){
        Tcl_Free(pDb->zProgress);
      }







|







3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
        Tcl_AppendResult(interp, pDb->zProgress, (char*)0);
      }
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
      sqlite3_progress_handler(pDb->db, 0, 0, 0);
#endif
    }else if( objc==4 ){
      char *zProgress;
      Tcl_Size len;
      int N;
      if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
        return TCL_ERROR;
      };
      if( pDb->zProgress ){
        Tcl_Free(pDb->zProgress);
      }
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zProfile ){
        Tcl_AppendResult(interp, pDb->zProfile, (char*)0);
      }
    }else{
      char *zProfile;
      int len;
      if( pDb->zProfile ){
        Tcl_Free(pDb->zProfile);
      }
      zProfile = Tcl_GetStringFromObj(objv[2], &len);
      if( zProfile && len>0 ){
        pDb->zProfile = Tcl_Alloc( len + 1 );
        memcpy(pDb->zProfile, zProfile, len+1);







|







3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zProfile ){
        Tcl_AppendResult(interp, pDb->zProfile, (char*)0);
      }
    }else{
      char *zProfile;
      Tcl_Size len;
      if( pDb->zProfile ){
        Tcl_Free(pDb->zProfile);
      }
      zProfile = Tcl_GetStringFromObj(objv[2], &len);
      if( zProfile && len>0 ){
        pDb->zProfile = Tcl_Alloc( len + 1 );
        memcpy(pDb->zProfile, zProfile, len+1);
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zTrace ){
        Tcl_AppendResult(interp, pDb->zTrace, (char*)0);
      }
    }else{
      char *zTrace;
      int len;
      if( pDb->zTrace ){
        Tcl_Free(pDb->zTrace);
      }
      zTrace = Tcl_GetStringFromObj(objv[2], &len);
      if( zTrace && len>0 ){
        pDb->zTrace = Tcl_Alloc( len + 1 );
        memcpy(pDb->zTrace, zTrace, len+1);







|







3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zTrace ){
        Tcl_AppendResult(interp, pDb->zTrace, (char*)0);
      }
    }else{
      char *zTrace;
      Tcl_Size len;
      if( pDb->zTrace ){
        Tcl_Free(pDb->zTrace);
      }
      zTrace = Tcl_GetStringFromObj(objv[2], &len);
      if( zTrace && len>0 ){
        pDb->zTrace = Tcl_Alloc( len + 1 );
        memcpy(pDb->zTrace, zTrace, len+1);
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zTraceV2 ){
        Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0);
      }
    }else{
      char *zTraceV2;
      int len;
      Tcl_WideInt wMask = 0;
      if( objc==4 ){
        static const char *TTYPE_strs[] = {
          "statement", "profile", "row", "close", 0
        };
        enum TTYPE_enum {
          TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE







|







3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
      return TCL_ERROR;
    }else if( objc==2 ){
      if( pDb->zTraceV2 ){
        Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0);
      }
    }else{
      char *zTraceV2;
      Tcl_Size len;
      Tcl_WideInt wMask = 0;
      if( objc==4 ){
        static const char *TTYPE_strs[] = {
          "statement", "profile", "row", "close", 0
        };
        enum TTYPE_enum {
          TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966





3967
3968
3969
3970


3971




3972
3973
3974
3975
3976
3977
3978
/* Because it accesses the file-system and uses persistent state, SQLite
** is not considered appropriate for safe interpreters.  Hence, we cause
** the _SafeInit() interfaces return TCL_ERROR.
*/
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}



#ifndef SQLITE_3_SUFFIX_ONLY





int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }


#endif





/*
** If the TCLSH macro is defined, add code to make a stand-alone program.
*/
#if defined(TCLSH)

/* This is the main routine for an ordinary TCL shell.  If there are







|
|
|
>
>
>
>
>
|
|
|
|
>
>
|
>
>
>
>







4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
/* Because it accesses the file-system and uses persistent state, SQLite
** is not considered appropriate for safe interpreters.  Hence, we cause
** the _SafeInit() interfaces return TCL_ERROR.
*/
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}

/*
** Versions of all of the above entry points that omit the "3" at the end
** of the name.  Years ago (circa 2004) the "3" was necessary to distinguish
** SQLite version 3 from Sqlite version 2.  But two decades have elapsed.
** SQLite2 is not longer a conflict.  So it is ok to omit the "3".
**
** Omitting the "3" helps TCL find the entry point.
*/
EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
EXTERN int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
EXTERN int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
EXTERN int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}

/* Also variants with a lowercase "s" */
EXTERN int sqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
EXTERN int sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}


/*
** If the TCLSH macro is defined, add code to make a stand-alone program.
*/
#if defined(TCLSH)

/* This is the main routine for an ordinary TCL shell.  If there are
Added src/tclsqlite.h.




















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
** 2024-07-30
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface to TCL as used by SQLite.
** SQLite subcomponents that use TCL (the libsqlite3.c interface library
** and various test*.c pieces) should #include this file rather than
** including tcl.h directly.
*/
/******  Any edits to this file must mirrored in tclsqlite.c ***********/

/* When compiling for Windows using STDCALL instead of CDECL calling
** conventions, the MSVC makefile has to build a customized version of
** the "tcl.h" header that specifies the calling conventions for each
** interface.  That customized "tcl.h" is named "sqlite_tcl.h".
*/
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"   /* Special case for Windows using STDCALL */
#else
# include <tcl.h>          /* All normal cases */
# ifndef SQLITE_TCLAPI
#   define SQLITE_TCLAPI
# endif
#endif

/******  Any edits to this file must mirrored in tclsqlite.c ***********/

/* Compatability between Tcl8.6 and Tcl9.0 */
#if TCL_MAJOR_VERSION==9
# define CONST const
#else
  typedef int Tcl_Size;
#endif

/******  Any edits to this file must mirrored in tclsqlite.c ***********/
Changes to src/test1.c.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#  if defined(__APPLE__)
#    include <sys/param.h>
#    include <sys/sysctl.h>
#  endif
#endif

#include "vdbeInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>

/*
** This is a copy of the first part of the SqliteDb structure in 
** tclsqlite.c.  We need it here so that the get_sqlite_pointer routine
** can extract the sqlite3* pointer from an existing Tcl SQLite







<
<
<
|
<







22
23
24
25
26
27
28



29

30
31
32
33
34
35
36
#  if defined(__APPLE__)
#    include <sys/param.h>
#    include <sys/sysctl.h>
#  endif
#endif

#include "vdbeInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>

/*
** This is a copy of the first part of the SqliteDb structure in 
** tclsqlite.c.  We need it here so that the get_sqlite_pointer routine
** can extract the sqlite3* pointer from an existing Tcl SQLite
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782

static int SQLITE_TCLAPI blobHandleFromObj(
  Tcl_Interp *interp, 
  Tcl_Obj *pObj,
  sqlite3_blob **ppBlob
){
  char *z;
  int n;

  z = Tcl_GetStringFromObj(pObj, &n);
  if( n==0 ){
    *ppBlob = 0;
  }else{
    int notUsed;
    Tcl_Channel channel;







|







1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778

static int SQLITE_TCLAPI blobHandleFromObj(
  Tcl_Interp *interp, 
  Tcl_Obj *pObj,
  sqlite3_blob **ppBlob
){
  char *z;
  Tcl_Size n;

  z = Tcl_GetStringFromObj(pObj, &n);
  if( n==0 ){
    *ppBlob = 0;
  }else{
    int notUsed;
    Tcl_Channel channel;
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
    } aTbl[] = {
      {"complex", SQLITE_SCANSTAT_COMPLEX},
      {"debug", -1},
      {0, 0}
    };

    Tcl_Obj **aFlag = 0;
    int nFlag = 0;
    int ii;

    if( Tcl_ListObjGetElements(interp, objv[2], &nFlag, &aFlag) ){
      return TCL_ERROR;
    }
    for(ii=0; ii<nFlag; ii++){
      int iVal = 0;
      int res = Tcl_GetIndexFromObjStruct(
          interp, aFlag[ii], aTbl, sizeof(aTbl[0]), "flag", 0, &iVal
      );
      if( res ) return TCL_ERROR;
      if( aTbl[iVal].flag==-1 ){
        bDebug = 1;







|





|







2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
    } aTbl[] = {
      {"complex", SQLITE_SCANSTAT_COMPLEX},
      {"debug", -1},
      {0, 0}
    };

    Tcl_Obj **aFlag = 0;
    Tcl_Size nFlag = 0;
    int ii;

    if( Tcl_ListObjGetElements(interp, objv[2], &nFlag, &aFlag) ){
      return TCL_ERROR;
    }
    for(ii=0; ii<(int)nFlag; ii++){
      int iVal = 0;
      int res = Tcl_GetIndexFromObjStruct(
          interp, aFlag[ii], aTbl, sizeof(aTbl[0]), "flag", 0, &iVal
      );
      if( res ) return TCL_ERROR;
      if( aTbl[iVal].flag==-1 ){
        bDebug = 1;
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
  int objc,
  Tcl_Obj *CONST objv[]
){
  int rc;
  sqlite3 *db;
  char *zName;
  unsigned char *pBlob;
  int nBlob;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zName = Tcl_GetString(objv[2]);







|







2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
  int objc,
  Tcl_Obj *CONST objv[]
){
  int rc;
  sqlite3 *db;
  char *zName;
  unsigned char *pBlob;
  Tcl_Size nBlob;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zName = Tcl_GetString(objv[2]);
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int res;
  unsigned char *p1;
  unsigned char *p2;
  int n1;
  int n2;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
    return TCL_ERROR;
  }

  p1 = Tcl_GetByteArrayFromObj(objv[1], &n1);







|
|







2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int res;
  unsigned char *p1;
  unsigned char *p2;
  Tcl_Size n1;
  Tcl_Size n2;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
    return TCL_ERROR;
  }

  p1 = Tcl_GetByteArrayFromObj(objv[1], &n1);
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int idx;
  int trueLength = 0;
  int bytes;
  char *value;
  int rc;
  char *toFree = 0;

  if( objc!=5 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",







|







4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int idx;
  Tcl_Size trueLength = 0;
  int bytes;
  char *value;
  int rc;
  char *toFree = 0;

  if( objc!=5 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
#ifndef SQLITE_OMIT_UTF16
  sqlite3_stmt *pStmt;
  int idx;
  int bytes;
  char *value;
  char *toFree = 0;
  int rc;
  int trueLength = 0;

  void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
  Tcl_Obj *oStmt    = objv[objc-4];
  Tcl_Obj *oN       = objv[objc-3];
  Tcl_Obj *oString  = objv[objc-2];
  Tcl_Obj *oBytes   = objv[objc-1];








|







4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
#ifndef SQLITE_OMIT_UTF16
  sqlite3_stmt *pStmt;
  int idx;
  int bytes;
  char *value;
  char *toFree = 0;
  int rc;
  Tcl_Size trueLength = 0;

  void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
  Tcl_Obj *oStmt    = objv[objc-4];
  Tcl_Obj *oN       = objv[objc-3];
  Tcl_Obj *oString  = objv[objc-2];
  Tcl_Obj *oBytes   = objv[objc-1];

4210
4211
4212
4213
4214
4215
4216

4217
4218
4219
4220
4221
4222
4223
4224
static int SQLITE_TCLAPI test_bind_blob(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;

  int len, idx;
  int bytes;
  char *value;
  int rc;
  sqlite3_destructor_type xDestructor = SQLITE_TRANSIENT;

  if( objc!=5 && objc!=6 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",







>
|







4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
static int SQLITE_TCLAPI test_bind_blob(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  Tcl_Size len;
  int idx;
  int bytes;
  char *value;
  int rc;
  sqlite3_destructor_type xDestructor = SQLITE_TRANSIENT;

  if( objc!=5 && objc!=6 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250

  value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len);
  if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;

  if( bytes>len ){
    char zBuf[200];
    sqlite3_snprintf(sizeof(zBuf), zBuf,
                     "cannot use %d blob bytes, have %d", bytes, len);
    Tcl_AppendResult(interp, zBuf, (char*)0);
    return TCL_ERROR;
  }

  rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor);
  if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
  if( rc!=SQLITE_OK ){







|







4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247

  value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len);
  if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;

  if( bytes>len ){
    char zBuf[200];
    sqlite3_snprintf(sizeof(zBuf), zBuf,
                     "cannot use %d blob bytes, have %d", bytes, (int)len);
    Tcl_AppendResult(interp, zBuf, (char*)0);
    return TCL_ERROR;
  }

  rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor);
  if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
  if( rc!=SQLITE_OK ){
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
      aData = a;
      break;
    }
    case 4: { /* BLOB */
      struct iovec *a = sqlite3_malloc( sizeof(struct iovec)*nData );
      if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
      for(j=0; j<nData; j++){
        int n = 0;
        unsigned char *v = Tcl_GetByteArrayFromObj(objv[i+i], &n);
        a[j].iov_len = n;
        a[j].iov_base = sqlite3_malloc64( n );
        if( a[j].iov_base==0 ){
          a[j].iov_len = 0;
        }else{
          memcpy(a[j].iov_base, v, n);
        }
      }







|

|







4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
      aData = a;
      break;
    }
    case 4: { /* BLOB */
      struct iovec *a = sqlite3_malloc( sizeof(struct iovec)*nData );
      if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
      for(j=0; j<nData; j++){
        Tcl_Size n = 0;
        unsigned char *v = Tcl_GetByteArrayFromObj(objv[i+i], &n);
        a[j].iov_len = (size_t)n;
        a[j].iov_base = sqlite3_malloc64( n );
        if( a[j].iov_base==0 ){
          a[j].iov_len = 0;
        }else{
          memcpy(a[j].iov_base, v, n);
        }
      }
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
  const void *zSql;
  const void *zTail = 0;
  Tcl_Obj *pTail = 0;
  sqlite3_stmt *pStmt = 0;
  char zBuf[50]; 
  int rc;
  int bytes;                /* The integer specified as arg 3 */
  int objlen;               /* The byte-array length of arg 2 */

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;







|







5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
  const void *zSql;
  const void *zTail = 0;
  Tcl_Obj *pTail = 0;
  sqlite3_stmt *pStmt = 0;
  char zBuf[50]; 
  int rc;
  int bytes;                /* The integer specified as arg 3 */
  Tcl_Size objlen;          /* The byte-array length of arg 2 */

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
  const void *zSql;
  const void *zTail = 0;
  Tcl_Obj *pTail = 0;
  sqlite3_stmt *pStmt = 0;
  char zBuf[50]; 
  int rc;
  int bytes;                /* The integer specified as arg 3 */
  int objlen;               /* The byte-array length of arg 2 */

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;







|







5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
  const void *zSql;
  const void *zTail = 0;
  Tcl_Obj *pTail = 0;
  sqlite3_stmt *pStmt = 0;
  char zBuf[50]; 
  int rc;
  int bytes;                /* The integer specified as arg 3 */
  Tcl_Size objlen;          /* The byte-array length of arg 2 */

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
  const char *zFilename;
  const char *zVfs;
  int flags = 0;
  sqlite3 *db;
  int rc;
  char zBuf[100];

  int nFlag;
  Tcl_Obj **apFlag;
  int i;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS");
    return TCL_ERROR;
  }
  zFilename = Tcl_GetString(objv[1]);
  zVfs = Tcl_GetString(objv[3]);







|

|







5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
  const char *zFilename;
  const char *zVfs;
  int flags = 0;
  sqlite3 *db;
  int rc;
  char zBuf[100];

  Tcl_Size nFlag;
  Tcl_Obj **apFlag;
  Tcl_Size i;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS");
    return TCL_ERROR;
  }
  zFilename = Tcl_GetString(objv[1]);
  zVfs = Tcl_GetString(objv[3]);
5962
5963
5964
5965
5966
5967
5968











































































































































5969
5970
5971
5972
5973
5974
5975
  pVar = Tcl_GetVar2Ex(interp, Tcl_GetString(objv[1]), 0, TCL_LEAVE_ERR_MSG);
  if( pVar==0 ) return TCL_ERROR;
  if( pVar->typePtr ){
    Tcl_SetObjResult(interp, Tcl_NewStringObj(pVar->typePtr->name, -1));
  }
  return TCL_OK;
}












































































































































/*
** Usage:  sqlite3_release_memory ?N?
**
** Attempt to release memory currently held but not actually required.
** The integer N is the number of bytes we are trying to release.  The 
** return value is the amount of memory actually released.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
  pVar = Tcl_GetVar2Ex(interp, Tcl_GetString(objv[1]), 0, TCL_LEAVE_ERR_MSG);
  if( pVar==0 ) return TCL_ERROR;
  if( pVar->typePtr ){
    Tcl_SetObjResult(interp, Tcl_NewStringObj(pVar->typePtr->name, -1));
  }
  return TCL_OK;
}

#include <ctype.h>

/*
** Usage:  fpnum_compare STRING1 STRING2
**
** Compare two strings.  Return true if the strings are the same and
** false if they differ.
**
** For this comparison, the strings are analyzed as a sequenced of
** whitespace separated tokens.  The whitespace is ignored.  Only the
** tokens are compared.  Comparison rules:
**
**   A.  Tokens that are not floating-point numbers must match exactly.
**
**   B.  Floating point number must have exactly the same digits before
**       the decimal point.
**
**   C.  Digits must match after the decimal point up to 15 digits,
**       taking rounding into consideration.
**
**   D.  An exponent on a floating point of the form "e+NN" will
**       match "e+N" if NN==N.  Likewise for the negative exponent.
**
** This routine is used for comparing results that might involve floating
** point values.  Tcl9.0 and Tcl8.6 differ in the number of significant
** digits that they show, so there is no way to write a portable test result
** without this routine.
**
** This routine is only called after [string compare] fails, which is seldom,
** so performance is not a pressing concern.  Better to get the correct answer
** slowly.
*/
static int SQLITE_TCLAPI fpnum_compare(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  const unsigned char *zA;
  const unsigned char *zB;
  int i, j;
  int nDigit;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "STRING1 STRING2");
    return TCL_ERROR;
  }
  zA = (const unsigned char*)Tcl_GetString(objv[1]);
  zB = (const unsigned char*)Tcl_GetString(objv[2]);
  i = j = 0;
  while( 1 ){
    /* Skip whitespace before and after tokens */
    while( isspace(zA[i]) ){ i++; }
    while( isspace(zB[j]) ){ j++; }

    if( zA[i]!=zB[j] ) break;                /* First character must match */
    if( zA[i]=='-' && isdigit(zA[i+1]) ){ i++; j++; }  /* Skip initial '-' */
    if( !isdigit(zA[i]) ){
      /* Not a number.  Must match exactly */
      while( !isspace(zA[i]) && zA[i] && zA[i]==zB[j] ){ i++; j++; }
      if( zA[i]!=zB[j] ) break;
      if( isspace(zA[i]) ) continue;
      break;
    }

    /* At this point we know we are dealing with a number zA[i] and zB[j]
    ** are both digits (leading "-" have been skipped).  See if they are
    ** the same number.  Start by matching digits before the decimal
    ** point, which must all be the same. */
    nDigit = 0;
    while( zA[i]==zB[j] && isdigit(zA[i]) ){ i++; j++; nDigit++; }
    if( zA[i]!=zB[j] ) break;
    if( zA[i]==0 ) break;
    if( zA[i]=='.' && zB[j]=='.' ){
      /* Count more matching digits after the decimal point */
      i++;
      j++;
      while( zA[i]==zB[j] && isdigit(zA[i]) ){ i++; j++; nDigit++; }
      if( zA[i]==0 ){
        while( zB[j]=='0' || (isdigit(zB[j]) && nDigit>=15) ){ j++; nDigit++; }
        break;
      }
      if( zB[j]==0 ){
        while( zA[i]=='0' || (isdigit(zA[i]) && nDigit>=15) ){ i++; nDigit++; }
        break;
      }
      if( isspace(zA[i]) && isspace(zB[j]) ) continue;

      if( isdigit(zA[i]) && isdigit(zB[j]) ){
        /* A and B are both digits, but different digits */
        if( zA[i]==zB[j]+1 && !isdigit(zA[i+1]) && isdigit(zB[j+1]) ){
          /* Is A a rounded up version of B? */
          j++;
          while( zB[j]=='9' ){ j++; nDigit++; }
          if( nDigit<14 && (!isdigit(zB[j]) || zB[j]<5) ) break;
          while( isdigit(zB[j]) ){ j++; }
          i++;
        }else if( zB[j]==zA[i]+1 && !isdigit(zB[j+1]) && isdigit(zA[i+1]) ){
          /* Is B a rounded up version of A? */
          i++;
          while( zA[i]=='9' ){ i++; nDigit++; }
          if( nDigit<14 && (!isdigit(zA[i]) || zA[i]<5) ) break;
          while( isdigit(zA[i]) ){ i++; }
          j++;
        }else{
          break;
        }
      }else if( !isdigit(zA[i]) && isdigit(zB[j]) ){
        while( zB[j]=='0' ){ j++; nDigit++; }
        if( nDigit<15 ) break;
        while( isdigit(zB[j]) ){ j++; }
      }else if( !isdigit(zB[j]) && isdigit(zA[i]) ){
        while( zA[i]=='0' ){ i++; nDigit++; }
        if( nDigit<15 ) break;
        while( isdigit(zA[i]) ){ i++; }
      }else{
        break;
      }
    }
    if( zA[i]=='e' && zB[j]=='e' ){
      i++;
      j++;
      if( (zA[i]=='+' || zA[i]=='-') && zB[j]==zA[i] ){  i++;  j++; }
      if( zA[i]!=zB[j] ){
        if( zA[i]=='0' && zA[i+1]==zB[j] ){ i++; }
        if( zB[j]=='0' && zB[j+1]==zA[i] ){ j++; }
      }
      while( zA[i]==zB[j] && isdigit(zA[i]) ){ i++; j++; }
      if( zA[i]!=zB[j] ) break;
      if( zA[i]==0 ) break;
      continue;
    }
  }
  while( isspace(zA[i]) ){ i++; }
  while( isspace(zB[j]) ){ j++; }  
  Tcl_SetObjResult(interp, Tcl_NewIntObj(zA[i]==0 && zB[j]==0));
  return TCL_OK;
}

/*
** Usage:  sqlite3_release_memory ?N?
**
** Attempt to release memory currently held but not actually required.
** The integer N is the number of bytes we are trying to release.  The 
** return value is the amount of memory actually released.
6651
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
#    define SQLITE_ENABLE_LOCKING_STYLE 0
#  endif
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
  {
    char *testPath;
    int rc;
    int nPwd;
    const char *zPwd;
    char proxyPath[400];
    
    zPwd = Tcl_GetStringFromObj(objv[2], &nPwd);
    if( sizeof(proxyPath)<nPwd+20 ){
      Tcl_AppendResult(interp, "PWD too big", (void*)0);
      return TCL_ERROR;







|







6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
#    define SQLITE_ENABLE_LOCKING_STYLE 0
#  endif
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
  {
    char *testPath;
    int rc;
    Tcl_Size nPwd;
    const char *zPwd;
    char proxyPath[400];
    
    zPwd = Tcl_GetStringFromObj(objv[2], &nPwd);
    if( sizeof(proxyPath)<nPwd+20 ){
      Tcl_AppendResult(interp, "PWD too big", (void*)0);
      return TCL_ERROR;
7921
7922
7923
7924
7925
7926
7927
7928
7929
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
7970
7971
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983
7984
7985
7986
7987
7988
7989
7990
7991
7992
7993
7994
7995
7996
7997
7998
7999
8000
8001
8002
8003
8004
8005
8006
8007
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021
8022
8023
8024
8025
8026
8027
8028
8029
8030
8031
8032
8033
8034
8035
8036
8037
8038
8039
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
    Tcl_AppendResult(interp, "wait failed: ", zBuf, (char*)0);
    CloseHandle(ev);
    return TCL_ERROR;
  }
  CloseHandle(ev);
  return TCL_OK;
}

/*
**      exists_win32_path PATH
**
** Returns non-zero if the specified path exists, whose fully qualified name
** may exceed 260 characters if it is prefixed with "\\?\".
*/
static int SQLITE_TCLAPI win32_exists_path(
  void *clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "PATH");
    return TCL_ERROR;
  }
  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
      GetFileAttributesW( Tcl_GetUnicode(objv[1]))!=INVALID_FILE_ATTRIBUTES ));
  return TCL_OK;
}

/*
**      find_win32_file PATTERN
**
** Returns a list of entries in a directory that match the specified pattern,
** whose fully qualified name may exceed 248 characters if it is prefixed with
** "\\?\".
*/
static int SQLITE_TCLAPI win32_find_file(
  void *clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  HANDLE hFindFile = INVALID_HANDLE_VALUE;
  WIN32_FIND_DATAW findData;
  Tcl_Obj *listObj;
  DWORD lastErrno;
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "PATTERN");
    return TCL_ERROR;
  }
  hFindFile = FindFirstFileW(Tcl_GetUnicode(objv[1]), &findData);
  if( hFindFile==INVALID_HANDLE_VALUE ){
    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
    return TCL_ERROR;
  }
  listObj = Tcl_NewObj();
  Tcl_IncrRefCount(listObj);
  do {
    Tcl_ListObjAppendElement(interp, listObj, Tcl_NewUnicodeObj(
        findData.cFileName, -1));
    Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(
        findData.dwFileAttributes));
  } while( FindNextFileW(hFindFile, &findData) );
  lastErrno = GetLastError();
  if( lastErrno!=NO_ERROR && lastErrno!=ERROR_NO_MORE_FILES ){
    FindClose(hFindFile);
    Tcl_DecrRefCount(listObj);
    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
    return TCL_ERROR;
  }
  FindClose(hFindFile);
  Tcl_SetObjResult(interp, listObj);
  return TCL_OK;
}

/*
**      delete_win32_file FILENAME
**
** Deletes the specified file, whose fully qualified name may exceed 260
** characters if it is prefixed with "\\?\".
*/
static int SQLITE_TCLAPI win32_delete_file(
  void *clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
    return TCL_ERROR;
  }
  if( !DeleteFileW(Tcl_GetUnicode(objv[1])) ){
    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
    return TCL_ERROR;
  }
  Tcl_ResetResult(interp);
  return TCL_OK;
}

/*
**      make_win32_dir DIRECTORY
**
** Creates the specified directory, whose fully qualified name may exceed 248
** characters if it is prefixed with "\\?\".
*/
static int SQLITE_TCLAPI win32_mkdir(
  void *clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
    return TCL_ERROR;
  }
  if( !CreateDirectoryW(Tcl_GetUnicode(objv[1]), NULL) ){
    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
    return TCL_ERROR;
  }
  Tcl_ResetResult(interp);
  return TCL_OK;
}

/*
**      remove_win32_dir DIRECTORY
**
** Removes the specified directory, whose fully qualified name may exceed 248
** characters if it is prefixed with "\\?\".
*/
static int SQLITE_TCLAPI win32_rmdir(
  void *clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
    return TCL_ERROR;
  }
  if( !RemoveDirectoryW(Tcl_GetUnicode(objv[1])) ){
    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
    return TCL_ERROR;
  }
  Tcl_ResetResult(interp);
  return TCL_OK;
}
#endif


/*
**      optimization_control DB OPT BOOLEAN
**
** Enable or disable query optimizations using the sqlite3_test_control()







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







8057
8058
8059
8060
8061
8062
8063











































































































































8064
8065
8066
8067
8068
8069
8070
    Tcl_AppendResult(interp, "wait failed: ", zBuf, (char*)0);
    CloseHandle(ev);
    return TCL_ERROR;
  }
  CloseHandle(ev);
  return TCL_OK;
}











































































































































#endif


/*
**      optimization_control DB OPT BOOLEAN
**
** Enable or disable query optimizations using the sqlite3_test_control()
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363
8364
8365
8366
8367
8368
8369
8370
8371
8372
8373
8374
8375
8376
8377
8378
8379
8380
8381
8382
8383
8384
8385
8386
8387
8388
8389
8390
8391
8392
8393
8394
8395
8396
8397
8398
8399
8400
8401
8402
8403
8404
8405
8406
8407
8408
8409
8410
8411
8412
8413
8414
8415
8416
8417
8418
8419
8420
8421
8422
8423
8424
8425
8426
8427
8428
8429
8430
8431
8432
8433
8434
8435
8436
8437
8438
8439
8440
8441
8442
8443
8444
8445
8446
8447
8448
8449
8450
8451
8452
8453
8454
8455
8456
8457
8458
8459
  rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0);
  if( rc!=SQLITE_OK ) goto sql_error;

  iB = sqlite3_column_count(pStmt)-1;
  for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
    int a = sqlite3_column_int(pStmt, 0);
    if( a!=sqlite3_column_int(pStmt, iB) ){
      Tcl_AppendResult(interp, "data error: (a!=b)", 0);
      return TCL_ERROR;
    }

    iCksum1 += (iCksum1 << 3) + (unsigned int)a;
  }
  rc = sqlite3_finalize(pStmt);
  if( rc!=SQLITE_OK ) goto sql_error;

  rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0);
  if( rc!=SQLITE_OK ) goto sql_error;
  for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){
    int a = sqlite3_column_int(pStmt, 0);
    iCksum2 += (iCksum2 << 3) + (unsigned int)a;
  }
  rc = sqlite3_finalize(pStmt);
  if( rc!=SQLITE_OK ) goto sql_error;

  if( iCksum1!=iCksum2 ){
    Tcl_AppendResult(interp, "checksum mismatch", 0);
    return TCL_ERROR;
  }

  return TCL_OK;
 sql_error:
  Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
  return TCL_ERROR;
}


#ifdef SQLITE_USER_AUTHENTICATION
#include "sqlite3userauth.h"
/*
** tclcmd:  sqlite3_user_authenticate DB USERNAME PASSWORD
*/
static int SQLITE_TCLAPI test_user_authenticate(
  ClientData clientData, /* Unused */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  char *zUser = 0;
  char *zPasswd = 0;
  int nPasswd = 0;
  sqlite3 *db;
  int rc;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zUser = Tcl_GetString(objv[2]);
  zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
  rc = sqlite3_user_authenticate(db, zUser, zPasswd, nPasswd);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}
#endif /* SQLITE_USER_AUTHENTICATION */

#ifdef SQLITE_USER_AUTHENTICATION
/*
** tclcmd:  sqlite3_user_add DB USERNAME PASSWORD ISADMIN
*/
static int SQLITE_TCLAPI test_user_add(
  ClientData clientData, /* Unused */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  char *zUser = 0;
  char *zPasswd = 0;
  int nPasswd = 0;
  int isAdmin = 0;
  sqlite3 *db;
  int rc;

  if( objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zUser = Tcl_GetString(objv[2]);
  zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
  Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
  rc = sqlite3_user_add(db, zUser, zPasswd, nPasswd, isAdmin);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}
#endif /* SQLITE_USER_AUTHENTICATION */

#ifdef SQLITE_USER_AUTHENTICATION
/*
** tclcmd:  sqlite3_user_change DB USERNAME PASSWORD ISADMIN
*/
static int SQLITE_TCLAPI test_user_change(
  ClientData clientData, /* Unused */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  char *zUser = 0;
  char *zPasswd = 0;
  int nPasswd = 0;
  int isAdmin = 0;
  sqlite3 *db;
  int rc;

  if( objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zUser = Tcl_GetString(objv[2]);
  zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
  Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
  rc = sqlite3_user_change(db, zUser, zPasswd, nPasswd, isAdmin);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}
#endif /* SQLITE_USER_AUTHENTICATION */

#ifdef SQLITE_USER_AUTHENTICATION
/*







|


















|





|

















|












|

















|














|

















|














|







8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363
8364
8365
8366
8367
8368
8369
8370
8371
8372
8373
8374
8375
8376
8377
8378
8379
8380
8381
8382
8383
8384
8385
8386
8387
8388
8389
8390
8391
8392
8393
8394
8395
8396
8397
8398
8399
8400
8401
8402
8403
8404
8405
8406
8407
8408
8409
8410
8411
8412
8413
8414
8415
8416
8417
8418
8419
8420
8421
8422
8423
8424
8425
8426
8427
8428
8429
8430
8431
8432
8433
8434
8435
8436
8437
8438
8439
8440
8441
8442
8443
8444
8445
8446
8447
8448
8449
8450
8451
8452
8453
8454
8455
8456
  rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0);
  if( rc!=SQLITE_OK ) goto sql_error;

  iB = sqlite3_column_count(pStmt)-1;
  for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
    int a = sqlite3_column_int(pStmt, 0);
    if( a!=sqlite3_column_int(pStmt, iB) ){
      Tcl_AppendResult(interp, "data error: (a!=b)", (void*)0);
      return TCL_ERROR;
    }

    iCksum1 += (iCksum1 << 3) + (unsigned int)a;
  }
  rc = sqlite3_finalize(pStmt);
  if( rc!=SQLITE_OK ) goto sql_error;

  rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0);
  if( rc!=SQLITE_OK ) goto sql_error;
  for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){
    int a = sqlite3_column_int(pStmt, 0);
    iCksum2 += (iCksum2 << 3) + (unsigned int)a;
  }
  rc = sqlite3_finalize(pStmt);
  if( rc!=SQLITE_OK ) goto sql_error;

  if( iCksum1!=iCksum2 ){
    Tcl_AppendResult(interp, "checksum mismatch", (void*)0);
    return TCL_ERROR;
  }

  return TCL_OK;
 sql_error:
  Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db),  (void*)0);
  return TCL_ERROR;
}


#ifdef SQLITE_USER_AUTHENTICATION
#include "sqlite3userauth.h"
/*
** tclcmd:  sqlite3_user_authenticate DB USERNAME PASSWORD
*/
static int SQLITE_TCLAPI test_user_authenticate(
  ClientData clientData, /* Unused */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  char *zUser = 0;
  char *zPasswd = 0;
  Tcl_Size nPasswd = 0;
  sqlite3 *db;
  int rc;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zUser = Tcl_GetString(objv[2]);
  zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
  rc = sqlite3_user_authenticate(db, zUser, zPasswd, (int)nPasswd);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}
#endif /* SQLITE_USER_AUTHENTICATION */

#ifdef SQLITE_USER_AUTHENTICATION
/*
** tclcmd:  sqlite3_user_add DB USERNAME PASSWORD ISADMIN
*/
static int SQLITE_TCLAPI test_user_add(
  ClientData clientData, /* Unused */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  char *zUser = 0;
  char *zPasswd = 0;
  Tcl_Size nPasswd = 0;
  int isAdmin = 0;
  sqlite3 *db;
  int rc;

  if( objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zUser = Tcl_GetString(objv[2]);
  zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
  Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
  rc = sqlite3_user_add(db, zUser, zPasswd, (int)nPasswd, isAdmin);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}
#endif /* SQLITE_USER_AUTHENTICATION */

#ifdef SQLITE_USER_AUTHENTICATION
/*
** tclcmd:  sqlite3_user_change DB USERNAME PASSWORD ISADMIN
*/
static int SQLITE_TCLAPI test_user_change(
  ClientData clientData, /* Unused */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  char *zUser = 0;
  char *zPasswd = 0;
  Tcl_Size nPasswd = 0;
  int isAdmin = 0;
  sqlite3 *db;
  int rc;

  if( objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  zUser = Tcl_GetString(objv[2]);
  zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
  Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
  rc = sqlite3_user_change(db, zUser, zPasswd, (int)nPasswd, isAdmin);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}
#endif /* SQLITE_USER_AUTHENTICATION */

#ifdef SQLITE_USER_AUTHENTICATION
/*
8729
8730
8731
8732
8733
8734
8735
8736
8737
8738
8739
8740
8741
8742
8743
8744
8745
8746
8747
8748
8749
8750
8751
8752
8753
8754
8755
8756
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db = 0;
  Tcl_WideInt iOff = 0;
  const unsigned char *aData = 0;
  int nData = 0;
  sqlite3_file *pFile = 0;
  int rc;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB OFFSET DATA");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  if( Tcl_GetWideIntFromObj(interp, objv[2], &iOff) ) return TCL_ERROR;
  aData = Tcl_GetByteArrayFromObj(objv[3], &nData);

  sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFile);
  rc = pFile->pMethods->xWrite(pFile, aData, nData, iOff);

  Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
  return TCL_OK;
}

/*
** Usage:  sqlite3_register_cksumvfs







|












|







8726
8727
8728
8729
8730
8731
8732
8733
8734
8735
8736
8737
8738
8739
8740
8741
8742
8743
8744
8745
8746
8747
8748
8749
8750
8751
8752
8753
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db = 0;
  Tcl_WideInt iOff = 0;
  const unsigned char *aData = 0;
  Tcl_Size nData = 0;
  sqlite3_file *pFile = 0;
  int rc;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB OFFSET DATA");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  if( Tcl_GetWideIntFromObj(interp, objv[2], &iOff) ) return TCL_ERROR;
  aData = Tcl_GetByteArrayFromObj(objv[3], &nData);

  sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFile);
  rc = pFile->pMethods->xWrite(pFile, aData, (int)(nData&0x7fffffff), iOff);

  Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
  return TCL_OK;
}

/*
** Usage:  sqlite3_register_cksumvfs
9154
9155
9156
9157
9158
9159
9160
9161
9162
9163
9164
9165
9166
9167
9168
9169
9170
9171
9172
     { "extra_schema_checks",           extra_schema_checks,    0},
     { "use_long_double",               use_long_double,        0},
     { "database_never_corrupt",        database_never_corrupt, 0},
     { "database_may_be_corrupt",       database_may_be_corrupt, 0},
     { "optimization_control",          optimization_control,0},
#if SQLITE_OS_WIN
     { "lock_win32_file",               win32_file_lock,    0 },
     { "exists_win32_path",             win32_exists_path,  0 },
     { "find_win32_file",               win32_find_file,    0 },
     { "delete_win32_file",             win32_delete_file,  0 },
     { "make_win32_dir",                win32_mkdir,        0 },
     { "remove_win32_dir",              win32_rmdir,        0 },
#endif
     { "tcl_objproc",                   runAsObjProc,       0 },

     /* sqlite3_column_*() API */
     { "sqlite3_column_count",          test_column_count  ,0 },
     { "sqlite3_data_count",            test_data_count    ,0 },
     { "sqlite3_column_type",           test_column_type   ,0 },







<
<
<
<
<







9151
9152
9153
9154
9155
9156
9157





9158
9159
9160
9161
9162
9163
9164
     { "extra_schema_checks",           extra_schema_checks,    0},
     { "use_long_double",               use_long_double,        0},
     { "database_never_corrupt",        database_never_corrupt, 0},
     { "database_may_be_corrupt",       database_may_be_corrupt, 0},
     { "optimization_control",          optimization_control,0},
#if SQLITE_OS_WIN
     { "lock_win32_file",               win32_file_lock,    0 },





#endif
     { "tcl_objproc",                   runAsObjProc,       0 },

     /* sqlite3_column_*() API */
     { "sqlite3_column_count",          test_column_count  ,0 },
     { "sqlite3_data_count",            test_data_count    ,0 },
     { "sqlite3_column_type",           test_column_type   ,0 },
9233
9234
9235
9236
9237
9238
9239

9240
9241
9242
9243
9244
9245
9246
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },
     { "add_test_function",       test_function, 0           },
     { "add_test_utf16bin_collate",    test_utf16bin_collate, 0        },
#endif
     { "sqlite3_test_errstr",     test_errstr, 0             },
     { "tcl_variable_type",       tcl_variable_type, 0       },

#ifndef SQLITE_OMIT_SHARED_CACHE
     { "sqlite3_enable_shared_cache", test_enable_shared, 0  },
     { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0},
#endif
     { "sqlite3_libversion_number", test_libversion_number, 0  },
     { "sqlite3_table_column_metadata", test_table_column_metadata, 0  },
#ifndef SQLITE_OMIT_INCRBLOB







>







9225
9226
9227
9228
9229
9230
9231
9232
9233
9234
9235
9236
9237
9238
9239
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },
     { "add_test_function",       test_function, 0           },
     { "add_test_utf16bin_collate",    test_utf16bin_collate, 0        },
#endif
     { "sqlite3_test_errstr",     test_errstr, 0             },
     { "tcl_variable_type",       tcl_variable_type, 0       },
     { "fpnum_compare",           fpnum_compare, 0           },
#ifndef SQLITE_OMIT_SHARED_CACHE
     { "sqlite3_enable_shared_cache", test_enable_shared, 0  },
     { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0},
#endif
     { "sqlite3_libversion_number", test_libversion_number, 0  },
     { "sqlite3_table_column_metadata", test_table_column_metadata, 0  },
#ifndef SQLITE_OMIT_INCRBLOB
Changes to src/test2.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**
*************************************************************************
** Code for testing the pager.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

extern const char *sqlite3ErrName(int);

/*







<
<
<
|
<







10
11
12
13
14
15
16



17

18
19
20
21
22
23
24
**
*************************************************************************
** Code for testing the pager.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

extern const char *sqlite3ErrName(int);

/*
Changes to src/test3.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
*************************************************************************
** Code for testing the btree.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "sqliteInt.h"
#include "btreeInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>

extern const char *sqlite3ErrName(int);

/*
** A bogus sqlite3 connection structure for use in the btree







<
<
<
|
<







11
12
13
14
15
16
17



18

19
20
21
22
23
24
25
*************************************************************************
** Code for testing the btree.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "sqliteInt.h"
#include "btreeInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>

extern const char *sqlite3ErrName(int);

/*
** A bogus sqlite3 connection structure for use in the btree
619
620
621
622
623
624
625

626
627
628
629
630
631
632
633
634
635
636

637
638
639
640
641
642
643
644
645
646
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *const objv[]
){
  BtCursor *pCur;
  int rc;
  BtreePayload x;


  if( objc!=4 && objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE");
    return TCL_ERROR;
  }

  memset(&x, 0, sizeof(x));
  if( objc==4 ){
    if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR;
    x.nKey = rc;
    x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &x.nData);

  }else{
    x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &rc);
    x.nKey = rc;
  }
  pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));

  sqlite3_mutex_enter(pCur->pBtree->db->mutex);
  sqlite3BtreeEnter(pCur->pBtree);
  rc = sqlite3BtreeInsert(pCur, &x, 0, 0);
  sqlite3BtreeLeave(pCur->pBtree);







>










|
>

|
|







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *const objv[]
){
  BtCursor *pCur;
  int rc;
  BtreePayload x;
  Tcl_Size n;

  if( objc!=4 && objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE");
    return TCL_ERROR;
  }

  memset(&x, 0, sizeof(x));
  if( objc==4 ){
    if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR;
    x.nKey = rc;
    x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &n);
    x.nData = (int)n;
  }else{
    x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &n);
    x.nKey = (int)n;
  }
  pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));

  sqlite3_mutex_enter(pCur->pBtree->db->mutex);
  sqlite3BtreeEnter(pCur->pBtree);
  rc = sqlite3BtreeInsert(pCur, &x, 0, 0);
  sqlite3BtreeLeave(pCur->pBtree);
Changes to src/test4.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the SQLite library in a multithreaded environment.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#if SQLITE_OS_UNIX && SQLITE_THREADSAFE
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sched.h>
#include <ctype.h>








<
<
<
|
<







8
9
10
11
12
13
14



15

16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the SQLite library in a multithreaded environment.
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#if SQLITE_OS_UNIX && SQLITE_THREADSAFE
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sched.h>
#include <ctype.h>

Changes to src/test5.c.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library. Specifically, the code in this file
** is used for testing the SQLite routines for converting between
** the various supported unicode encodings.
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>

/*
** The first argument is a TCL UTF-8 string. Return the byte array
** object with the encoded representation of the string, including
** the NULL terminator.
*/
static int SQLITE_TCLAPI binarize(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int len;
  char *bytes;
  Tcl_Obj *pRet;
  assert(objc==2);

  bytes = Tcl_GetStringFromObj(objv[1], &len);
  pRet = Tcl_NewByteArrayObj((u8*)bytes, len+1);
  Tcl_SetObjResult(interp, pRet);







<
<
<
|
<














|







13
14
15
16
17
18
19



20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library. Specifically, the code in this file
** is used for testing the SQLite routines for converting between
** the various supported unicode encodings.
*/
#include "sqliteInt.h"
#include "vdbeInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>

/*
** The first argument is a TCL UTF-8 string. Return the byte array
** object with the encoded representation of the string, including
** the NULL terminator.
*/
static int SQLITE_TCLAPI binarize(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_Size len;
  char *bytes;
  Tcl_Obj *pRet;
  assert(objc==2);

  bytes = Tcl_GetStringFromObj(objv[1], &len);
  pRet = Tcl_NewByteArrayObj((u8*)bytes, len+1);
  Tcl_SetObjResult(interp, pRet);
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  Tcl_Obj *CONST objv[]
){
  u8 enc_from;
  u8 enc_to;
  sqlite3_value *pVal;

  char *z;
  int len;
  void (*xDel)(void *p) = SQLITE_STATIC;

  if( objc!=4 && objc!=5 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_GetStringFromObj(objv[0], 0), 
        " <string/blob> <from enc> <to enc>", 0
    );







|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  Tcl_Obj *CONST objv[]
){
  u8 enc_from;
  u8 enc_to;
  sqlite3_value *pVal;

  char *z;
  Tcl_Size len;
  void (*xDel)(void *p) = SQLITE_STATIC;

  if( objc!=4 && objc!=5 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_GetStringFromObj(objv[0], 0), 
        " <string/blob> <from enc> <to enc>", 0
    );
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
      z = sqlite3_mprintf("%s", z);
    }
    sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
  }else{
    z = (char*)Tcl_GetByteArrayFromObj(objv[1], &len);
    if( objc==5 ){
      char *zTmp = z;
      z = sqlite3_malloc(len);
      memcpy(z, zTmp, len);
    }
    sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
  }

  z = (char *)sqlite3ValueText(pVal, enc_to);
  len = sqlite3ValueBytes(pVal, enc_to) + (enc_to==SQLITE_UTF8?1:2);







|







156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
      z = sqlite3_mprintf("%s", z);
    }
    sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
  }else{
    z = (char*)Tcl_GetByteArrayFromObj(objv[1], &len);
    if( objc==5 ){
      char *zTmp = z;
      z = sqlite3_malloc64(len);
      memcpy(z, zTmp, len);
    }
    sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
  }

  z = (char *)sqlite3ValueText(pVal, enc_to);
  len = sqlite3ValueBytes(pVal, enc_to) + (enc_to==SQLITE_UTF8?1:2);
Changes to src/test6.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
**
** This file contains code that modified the OS layer in order to simulate
** the effect on the database file of an OS crash or power failure.  This
** is used to test the ability of SQLite to recover from those situations.
*/
#if SQLITE_TEST          /* This file is used for testing only */
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

#ifndef SQLITE_OMIT_DISKIO  /* This file is a no-op if disk I/O is disabled */

/* #define TRACE_CRASHTEST */

typedef struct CrashFile CrashFile;
typedef struct CrashGlobal CrashGlobal;







<
<
<
|
<







12
13
14
15
16
17
18



19

20
21
22
23
24
25
26
**
** This file contains code that modified the OS layer in order to simulate
** the effect on the database file of an OS crash or power failure.  This
** is used to test the ability of SQLite to recover from those situations.
*/
#if SQLITE_TEST          /* This file is used for testing only */
#include "sqliteInt.h"



#include "tclsqlite.h"


#ifndef SQLITE_OMIT_DISKIO  /* This file is a no-op if disk I/O is disabled */

/* #define TRACE_CRASHTEST */

typedef struct CrashFile CrashFile;
typedef struct CrashGlobal CrashGlobal;
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
  int i;
  int iDc = 0;
  int iSectorSize = 0;
  int setSectorsize = 0;
  int setDeviceChar = 0;

  for(i=0; i<objc; i+=2){
    int nOpt;
    char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);

    if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt))
     && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
    ){
      Tcl_AppendResult(interp,
        "Bad option: \"", zOpt,







|







743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
  int i;
  int iDc = 0;
  int iSectorSize = 0;
  int setSectorsize = 0;
  int setDeviceChar = 0;

  for(i=0; i<objc; i+=2){
    Tcl_Size nOpt;
    char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);

    if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt))
     && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
    ){
      Tcl_AppendResult(interp,
        "Bad option: \"", zOpt,
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
      if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
        return TCL_ERROR;
      }
      setSectorsize = 1;
    }else{
      int j;
      Tcl_Obj **apObj;
      int nObj;
      if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
        return TCL_ERROR;
      }
      for(j=0; j<nObj; j++){
        int rc;
        int iChoice;
        Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
        Tcl_IncrRefCount(pFlag);
        Tcl_UtfToLower(Tcl_GetString(pFlag));

        rc = Tcl_GetIndexFromObjStruct(







|



|







768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
      if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
        return TCL_ERROR;
      }
      setSectorsize = 1;
    }else{
      int j;
      Tcl_Obj **apObj;
      Tcl_Size nObj;
      if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
        return TCL_ERROR;
      }
      for(j=0; j<(int)nObj; j++){
        int rc;
        int iChoice;
        Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
        Tcl_IncrRefCount(pFlag);
        Tcl_UtfToLower(Tcl_GetString(pFlag));

        rc = Tcl_GetIndexFromObjStruct(
921
922
923
924
925
926
927

928
929
930
931
932
933
934
935
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int iDelay;
  const char *zCrashFile;

  int nCrashFile, iDc, iSectorSize;

  iDc = -1;
  iSectorSize = -1;

  if( objc<3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
    goto error;







>
|







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int iDelay;
  const char *zCrashFile;
  Tcl_Size nCrashFile;
  int iDc, iSectorSize;

  iDc = -1;
  iSectorSize = -1;

  if( objc<3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
    goto error;
Changes to src/test8.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

typedef struct echo_vtab echo_vtab;
typedef struct echo_cursor echo_cursor;







<
<
<
|
<







10
11
12
13
14
15
16



17

18
19
20
21
22
23
24
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

typedef struct echo_vtab echo_vtab;
typedef struct echo_cursor echo_cursor;
Changes to src/test9.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
*************************************************************************
**
** This file contains obscure tests of the C-interface required
** for completeness. Test code is written in C for these cases
** as there is not much point in binding to Tcl.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>

/*
** c_collation_test
*/
static int SQLITE_TCLAPI c_collation_test(







<
<
<
|
<







11
12
13
14
15
16
17



18

19
20
21
22
23
24
25
*************************************************************************
**
** This file contains obscure tests of the C-interface required
** for completeness. Test code is written in C for these cases
** as there is not much point in binding to Tcl.
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>

/*
** c_collation_test
*/
static int SQLITE_TCLAPI c_collation_test(
Changes to src/test_async.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
**
*************************************************************************
**
** This file contains a binding of the asynchronous IO extension interface
** (defined in ext/async/sqlite3async.h) to Tcl.
*/

#define TCL_THREADS 
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

#ifdef SQLITE_ENABLE_ASYNCIO

#include "sqlite3async.h"
#include "sqlite3.h"
#include <assert.h>








|
<
<
<
|
<
<
<
<







10
11
12
13
14
15
16
17



18




19
20
21
22
23
24
25
**
*************************************************************************
**
** This file contains a binding of the asynchronous IO extension interface
** (defined in ext/async/sqlite3async.h) to Tcl.
*/

#define TCL_THREADS



#include "tclsqlite.h"





#ifdef SQLITE_ENABLE_ASYNCIO

#include "sqlite3async.h"
#include "sqlite3.h"
#include <assert.h>

Changes to src/test_autoext.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
** 2006 August 23
**
** 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.
**
*************************************************************************
** Test extension for testing the sqlite3_auto_extension() function.
*/
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif
#include "sqlite3ext.h"

#ifndef SQLITE_OMIT_LOAD_EXTENSION
SQLITE_EXTENSION_INIT1

/*
** The sqr() SQL function returns the square of its input value.













<
<
<
|
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13



14




15
16
17
18
19
20
21
/*
** 2006 August 23
**
** 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.
**
*************************************************************************
** Test extension for testing the sqlite3_auto_extension() function.
*/



#include "tclsqlite.h"




#include "sqlite3ext.h"

#ifndef SQLITE_OMIT_LOAD_EXTENSION
SQLITE_EXTENSION_INIT1

/*
** The sqr() SQL function returns the square of its input value.
Changes to src/test_backup.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains test logic for the sqlite3_backup() interface.
**
*/

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif
#include "sqlite3.h"
#include <assert.h>

/* These functions are implemented in main.c. */
extern const char *sqlite3ErrName(int);

/* These functions are implemented in test1.c. */







<
<
<
|
<
<
<
<







9
10
11
12
13
14
15



16




17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains test logic for the sqlite3_backup() interface.
**
*/




#include "tclsqlite.h"




#include "sqlite3.h"
#include <assert.h>

/* These functions are implemented in main.c. */
extern const char *sqlite3ErrName(int);

/* These functions are implemented in test1.c. */
Changes to src/test_bestindex.c.
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
** for the current scan. The leftmost column returned by the SELECT is assumed
** to contain the rowid. Other columns must follow, in order from left to
** right.
*/


#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

#ifndef SQLITE_OMIT_VIRTUALTABLE


typedef struct tcl_vtab tcl_vtab;
typedef struct tcl_cursor tcl_cursor;
typedef struct TestFindFunction TestFindFunction;







<
<
<
|
<







89
90
91
92
93
94
95



96

97
98
99
100
101
102
103
** for the current scan. The leftmost column returned by the SELECT is assumed
** to contain the rowid. Other columns must follow, in order from left to
** right.
*/


#include "sqliteInt.h"



#include "tclsqlite.h"


#ifndef SQLITE_OMIT_VIRTUALTABLE


typedef struct tcl_vtab tcl_vtab;
typedef struct tcl_cursor tcl_cursor;
typedef struct TestFindFunction TestFindFunction;
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
    ** list object with an even number of elements. The first element of each
    ** pair must be one of:
    ** 
    **   "sql"          (SQL statement to return data)
    */
    Tcl_Obj *pRes = Tcl_GetObjResult(interp);
    Tcl_Obj **apElem = 0;
    int nElem;
    rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
    if( rc!=TCL_OK ){
      const char *zErr = Tcl_GetStringResult(interp);
      rc = SQLITE_ERROR;
      pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
    }else{
      for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
        const char *zCmd = Tcl_GetString(apElem[ii]);
        Tcl_Obj *p = apElem[ii+1];
        if( sqlite3_stricmp("sql", zCmd)==0 ){
          const char *zSql = Tcl_GetString(p);
          rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
          if( rc!=SQLITE_OK ){
            const char *zErr = sqlite3_errmsg(pTab->db);







|






|







344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
    ** list object with an even number of elements. The first element of each
    ** pair must be one of:
    ** 
    **   "sql"          (SQL statement to return data)
    */
    Tcl_Obj *pRes = Tcl_GetObjResult(interp);
    Tcl_Obj **apElem = 0;
    Tcl_Size nElem;
    rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
    if( rc!=TCL_OK ){
      const char *zErr = Tcl_GetStringResult(interp);
      rc = SQLITE_ERROR;
      pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
    }else{
      for(ii=0; rc==SQLITE_OK && ii<(int)nElem; ii+=2){
        const char *zCmd = Tcl_GetString(apElem[ii]);
        Tcl_Obj *p = apElem[ii+1];
        if( sqlite3_stricmp("sql", zCmd)==0 ){
          const char *zSql = Tcl_GetString(p);
          rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
          if( rc!=SQLITE_OK ){
            const char *zErr = sqlite3_errmsg(pTab->db);
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
    **   "use"              (index of used constraint in aConstraint[])
    **   "idxnum"           (value of idxNum field)
    **   "idxstr"           (value of idxStr field)
    **   "omit"             (index of omitted constraint in aConstraint[])
    */
    Tcl_Obj *pRes = Tcl_GetObjResult(interp);
    Tcl_Obj **apElem = 0;
    int nElem;
    rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
    if( rc!=TCL_OK ){
      const char *zErr = Tcl_GetStringResult(interp);
      rc = SQLITE_ERROR;
      pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
    }else{
      int ii;
      int iArgv = 1;
      for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
        const char *zCmd = Tcl_GetString(apElem[ii]);
        Tcl_Obj *p = apElem[ii+1];
        if( sqlite3_stricmp("cost", zCmd)==0 ){
          rc = Tcl_GetDoubleFromObj(interp, p, &pIdxInfo->estimatedCost);
        }else
        if( sqlite3_stricmp("orderby", zCmd)==0 ){
          rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->orderByConsumed);







|








|







656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
    **   "use"              (index of used constraint in aConstraint[])
    **   "idxnum"           (value of idxNum field)
    **   "idxstr"           (value of idxStr field)
    **   "omit"             (index of omitted constraint in aConstraint[])
    */
    Tcl_Obj *pRes = Tcl_GetObjResult(interp);
    Tcl_Obj **apElem = 0;
    Tcl_Size nElem;
    rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
    if( rc!=TCL_OK ){
      const char *zErr = Tcl_GetStringResult(interp);
      rc = SQLITE_ERROR;
      pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
    }else{
      int ii;
      int iArgv = 1;
      for(ii=0; rc==SQLITE_OK && ii<(int)nElem; ii+=2){
        const char *zCmd = Tcl_GetString(apElem[ii]);
        Tcl_Obj *p = apElem[ii+1];
        if( sqlite3_stricmp("cost", zCmd)==0 ){
          rc = Tcl_GetDoubleFromObj(interp, p, &pIdxInfo->estimatedCost);
        }else
        if( sqlite3_stricmp("orderby", zCmd)==0 ){
          rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->orderByConsumed);
Changes to src/test_blob.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifndef SQLITE_OMIT_INCRBLOB

/* These functions are implemented in main.c. */
extern const char *sqlite3ErrName(int);







<
<
<
|
<







8
9
10
11
12
13
14



15

16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifndef SQLITE_OMIT_INCRBLOB

/* These functions are implemented in main.c. */
extern const char *sqlite3ErrName(int);
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
*/
static int blobHandleFromObj(
  Tcl_Interp *interp, 
  Tcl_Obj *pObj,
  sqlite3_blob **ppBlob
){
  char *z;
  int n;

  z = Tcl_GetStringFromObj(pObj, &n);
  if( n==0 ){
    *ppBlob = 0;
  }else if( n>9 && 0==memcmp("incrblob_", z, 9) ){
    int notUsed;
    Tcl_Channel channel;







|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
*/
static int blobHandleFromObj(
  Tcl_Interp *interp, 
  Tcl_Obj *pObj,
  sqlite3_blob **ppBlob
){
  char *z;
  Tcl_Size n;

  z = Tcl_GetStringFromObj(pObj, &n);
  if( n==0 ){
    *ppBlob = 0;
  }else if( n>9 && 0==memcmp("incrblob_", z, 9) ){
    int notUsed;
    Tcl_Channel channel;
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
}

/*
** Like Tcl_GetString(), except that if the string is 0 bytes in size, a
** NULL Pointer is returned.
*/
static char *blobStringFromObj(Tcl_Obj *pObj){
  int n;
  char *z;
  z = Tcl_GetStringFromObj(pObj, &n);
  return (n ? z : 0);
}

/*
** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME







|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
}

/*
** Like Tcl_GetString(), except that if the string is 0 bytes in size, a
** NULL Pointer is returned.
*/
static char *blobStringFromObj(Tcl_Obj *pObj){
  Tcl_Size n;
  char *z;
  z = Tcl_GetStringFromObj(pObj, &n);
  return (n ? z : 0);
}

/*
** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  sqlite3 *db;
  const char *zDb;
  const char *zTable;
  const char *zColumn;
  Tcl_WideInt iRowid;
  int flags;
  const char *zVarname;
  int nVarname;

  sqlite3_blob *pBlob = (sqlite3_blob*)&flags;   /* Non-zero initialization */
  int rc;

  if( objc!=8 ){
    const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME";
    Tcl_WrongNumArgs(interp, 1, objv, zUsage);







|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  sqlite3 *db;
  const char *zDb;
  const char *zTable;
  const char *zColumn;
  Tcl_WideInt iRowid;
  int flags;
  const char *zVarname;
  Tcl_Size nVarname;

  sqlite3_blob *pBlob = (sqlite3_blob*)&flags;   /* Non-zero initialization */
  int rc;

  if( objc!=8 ){
    const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME";
    Tcl_WrongNumArgs(interp, 1, objv, zUsage);
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291
292
293
294
295
296

297
298
299
300
301
302
303
304
305
306
307
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3_blob *pBlob;
  int iOffset;
  int rc;

  unsigned char *zBuf;

  int nBuf;
  
  if( objc!=4 && objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?");
    return TCL_ERROR;
  }

  if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
  if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ 
    return TCL_ERROR;
  }

  zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf);

  if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){
    return TCL_ERROR;
  }
  rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset);
  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
  }

  return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
}
#endif /* SQLITE_OMIT_INCRBLOB */







>
|












>
|


|







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3_blob *pBlob;
  int iOffset;
  int rc;

  unsigned char *zBuf;
  Tcl_Size nBuf;
  int n;
  
  if( objc!=4 && objc!=5 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?");
    return TCL_ERROR;
  }

  if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
  if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ 
    return TCL_ERROR;
  }

  zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf);
  n = (int)(nBuf & 0x7fffffff);
  if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &n) ){
    return TCL_ERROR;
  }
  rc = sqlite3_blob_write(pBlob, zBuf, n, iOffset);
  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
  }

  return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
}
#endif /* SQLITE_OMIT_INCRBLOB */
Changes to src/test_btree.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**
*************************************************************************
** Code for testing the btree.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "btreeInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

/*
** Usage: sqlite3_shared_cache_report
**
** Return a list of file that are shared and the number of
** references to each file.
*/







<
<
<
|
<







10
11
12
13
14
15
16



17

18
19
20
21
22
23
24
**
*************************************************************************
** Code for testing the btree.c module in SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
*/
#include "btreeInt.h"



#include "tclsqlite.h"


/*
** Usage: sqlite3_shared_cache_report
**
** Return a list of file that are shared and the number of
** references to each file.
*/
Changes to src/test_config.c.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "sqliteLimit.h"

#include "sqliteInt.h"
#if SQLITE_OS_WIN
#  include "os_win.h"
#endif

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>

/*
** Macro to stringify the results of the evaluation a pre-processor
** macro. i.e. so that STRINGVALUE(SQLITE_NOMEM) -> "7".
*/







<
<
<
|
<







20
21
22
23
24
25
26



27

28
29
30
31
32
33
34
#include "sqliteLimit.h"

#include "sqliteInt.h"
#if SQLITE_OS_WIN
#  include "os_win.h"
#endif




#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>

/*
** Macro to stringify the results of the evaluation a pre-processor
** macro. i.e. so that STRINGVALUE(SQLITE_NOMEM) -> "7".
*/
Changes to src/test_demovfs.c.
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
}

#endif /* !defined(SQLITE_TEST) || SQLITE_OS_UNIX */


#ifdef SQLITE_TEST

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

#if SQLITE_OS_UNIX
static int SQLITE_TCLAPI register_demovfs(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */







<
<
<
|
<
<
<
<







641
642
643
644
645
646
647



648




649
650
651
652
653
654
655
}

#endif /* !defined(SQLITE_TEST) || SQLITE_OS_UNIX */


#ifdef SQLITE_TEST




#include "tclsqlite.h"





#if SQLITE_OS_UNIX
static int SQLITE_TCLAPI register_demovfs(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
Changes to src/test_fs.c.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
** contents of the file-system, starting at "/". To restrict the search
** space, the virtual table supports LIKE and GLOB constraints on the
** 'path' column. For example:
**
**   SELECT * FROM fstree WHERE path LIKE '/home/dan/sqlite/%'
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#if SQLITE_OS_UNIX || defined(__MINGW_H)







<
<
<
|
<
<







58
59
60
61
62
63
64



65


66
67
68
69
70
71
72
** contents of the file-system, starting at "/". To restrict the search
** space, the virtual table supports LIKE and GLOB constraints on the
** 'path' column. For example:
**
**   SELECT * FROM fstree WHERE path LIKE '/home/dan/sqlite/%'
*/
#include "sqliteInt.h"



#include "tclsqlite.h"


#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#if SQLITE_OS_UNIX || defined(__MINGW_H)
Changes to src/test_func.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** implements new SQL functions used by the test scripts.
*/
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "sqliteInt.h"
#include "vdbeInt.h"








<
<
<
|
<







9
10
11
12
13
14
15



16

17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** implements new SQL functions used by the test scripts.
*/
#include "sqlite3.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "sqliteInt.h"
#include "vdbeInt.h"

Changes to src/test_hexio.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
** database files and displaying the content of those files as
** hexadecimal.  We could, in theory, use the built-in "binary"
** command of TCL to do a lot of this, but there are some issues
** with historical versions of the "binary" command.  So it seems
** easier and safer to build our own mechanism.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>


/*
** Convert binary to hex.  The input zBuf[] contains N bytes of







<
<
<
|
<







14
15
16
17
18
19
20



21

22
23
24
25
26
27
28
** database files and displaying the content of those files as
** hexadecimal.  We could, in theory, use the built-in "binary"
** command of TCL to do a lot of this, but there are some issues
** with historical versions of the "binary" command.  So it seems
** easier and safer to build our own mechanism.
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>


/*
** Convert binary to hex.  The input zBuf[] contains N bytes of
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
static int SQLITE_TCLAPI hexio_write(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int offset;

  int nIn, nOut, written;
  const char *zFile;
  const unsigned char *zIn;
  unsigned char *aOut;
  FILE *out;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
  zFile = Tcl_GetString(objv[1]);
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn);
  aOut = sqlite3_malloc( 1 + nIn/2 );
  if( aOut==0 ){
    return TCL_ERROR;
  }
  nOut = sqlite3TestHexToBin(zIn, nIn, aOut);
  out = fopen(zFile, "r+b");
  if( out==0 ){
    out = fopen(zFile, "r+");
  }
  if( out==0 ){
    Tcl_AppendResult(interp, "cannot open output file ", zFile, 0);
    return TCL_ERROR;







>
|












|



|







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
static int SQLITE_TCLAPI hexio_write(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int offset;
  Tcl_Size nIn;
  int nOut, written;
  const char *zFile;
  const unsigned char *zIn;
  unsigned char *aOut;
  FILE *out;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
  zFile = Tcl_GetString(objv[1]);
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn);
  aOut = sqlite3_malloc64( 1 + nIn/2 );
  if( aOut==0 ){
    return TCL_ERROR;
  }
  nOut = sqlite3TestHexToBin(zIn, (int)nIn, aOut);
  out = fopen(zFile, "r+b");
  if( out==0 ){
    out = fopen(zFile, "r+");
  }
  if( out==0 ){
    Tcl_AppendResult(interp, "cannot open output file ", zFile, 0);
    return TCL_ERROR;
199
200
201
202
203
204
205

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
static int SQLITE_TCLAPI hexio_get_int(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int val;

  int nIn, nOut;
  const unsigned char *zIn;
  unsigned char *aOut;
  unsigned char aNum[4];

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA");
    return TCL_ERROR;
  }
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn);
  aOut = sqlite3_malloc( 1 + nIn/2 );
  if( aOut==0 ){
    return TCL_ERROR;
  }
  nOut = sqlite3TestHexToBin(zIn, nIn, aOut);
  if( nOut>=4 ){
    memcpy(aNum, aOut, 4);
  }else{
    memset(aNum, 0, sizeof(aNum));
    memcpy(&aNum[4-nOut], aOut, nOut);
  }
  sqlite3_free(aOut);







>
|









|



|







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
static int SQLITE_TCLAPI hexio_get_int(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int val;
  Tcl_Size nIn;
  int nOut;
  const unsigned char *zIn;
  unsigned char *aOut;
  unsigned char aNum[4];

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA");
    return TCL_ERROR;
  }
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn);
  aOut = sqlite3_malloc64( 1 + nIn/2 );
  if( aOut==0 ){
    return TCL_ERROR;
  }
  nOut = sqlite3TestHexToBin(zIn, (int)nIn, aOut);
  if( nOut>=4 ){
    memcpy(aNum, aOut, 4);
  }else{
    memset(aNum, 0, sizeof(aNum));
    memcpy(&aNum[4-nOut], aOut, nOut);
  }
  sqlite3_free(aOut);
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
static int SQLITE_TCLAPI utf8_to_utf8(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
#ifdef SQLITE_DEBUG
  int n;
  int nOut;
  const unsigned char *zOrig;
  unsigned char *z;
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HEX");
    return TCL_ERROR;
  }
  zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n);
  z = sqlite3_malloc( n+4 );
  n = sqlite3TestHexToBin(zOrig, n, z);
  z[n] = 0;
  nOut = sqlite3Utf8To8(z);
  sqlite3TestBinToHex(z,nOut);
  Tcl_AppendResult(interp, (char*)z, 0);
  sqlite3_free(z);
  return TCL_OK;
#else







|








|
|







294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
static int SQLITE_TCLAPI utf8_to_utf8(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
#ifdef SQLITE_DEBUG
  Tcl_Size n;
  int nOut;
  const unsigned char *zOrig;
  unsigned char *z;
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HEX");
    return TCL_ERROR;
  }
  zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n);
  z = sqlite3_malloc64( n+4 );
  n = sqlite3TestHexToBin(zOrig, (int)n, z);
  z[n] = 0;
  nOut = sqlite3Utf8To8(z);
  sqlite3TestBinToHex(z,nOut);
  Tcl_AppendResult(interp, (char*)z, 0);
  sqlite3_free(z);
  return TCL_OK;
#else
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
*/
static int SQLITE_TCLAPI read_fts3varint(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int nBlob;
  unsigned char *zBlob;
  sqlite3_int64 iVal;
  int nVal;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "BLOB VARNAME");
    return TCL_ERROR;







|







355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
*/
static int SQLITE_TCLAPI read_fts3varint(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_Size nBlob;
  unsigned char *zBlob;
  sqlite3_int64 iVal;
  int nVal;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "BLOB VARNAME");
    return TCL_ERROR;
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
static int SQLITE_TCLAPI make_fts3record(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_Obj **aArg = 0;
  int nArg = 0;
  unsigned char *aOut = 0;
  int nOut = 0;
  int nAlloc = 0;
  int i;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "LIST");
    return TCL_ERROR;
  }
  if( Tcl_ListObjGetElements(interp, objv[1], &nArg, &aArg) ){
    return TCL_ERROR;
  }

  for(i=0; i<nArg; i++){
    sqlite3_int64 iVal;
    if( TCL_OK==Tcl_GetWideIntFromObj(0, aArg[i], &iVal) ){
      if( nOut+10>nAlloc ){
        int nNew = nAlloc?nAlloc*2:128;
        unsigned char *aNew = sqlite3_realloc(aOut, nNew);
        if( aNew==0 ){
          sqlite3_free(aOut);
          return TCL_ERROR;
        }
        aOut = aNew;
        nAlloc = nNew;
      }
      nOut += putFts3Varint((char*)&aOut[nOut], iVal);
    }else{
      int nVal = 0;
      char *zVal = Tcl_GetStringFromObj(aArg[i], &nVal);
      while( (nOut + nVal)>nAlloc ){
        int nNew = nAlloc?nAlloc*2:128;
        unsigned char *aNew = sqlite3_realloc(aOut, nNew);
        if( aNew==0 ){
          sqlite3_free(aOut);
          return TCL_ERROR;
        }
        aOut = aNew;
        nAlloc = nNew;
      }







|

|
|










|
|













|


|
|







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
static int SQLITE_TCLAPI make_fts3record(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_Obj **aArg = 0;
  Tcl_Size nArg = 0;
  unsigned char *aOut = 0;
  sqlite3_int64 nOut = 0;
  sqlite3_int64 nAlloc = 0;
  int i;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "LIST");
    return TCL_ERROR;
  }
  if( Tcl_ListObjGetElements(interp, objv[1], &nArg, &aArg) ){
    return TCL_ERROR;
  }

  for(i=0; i<(int)nArg; i++){
    Tcl_WideInt iVal;
    if( TCL_OK==Tcl_GetWideIntFromObj(0, aArg[i], &iVal) ){
      if( nOut+10>nAlloc ){
        int nNew = nAlloc?nAlloc*2:128;
        unsigned char *aNew = sqlite3_realloc(aOut, nNew);
        if( aNew==0 ){
          sqlite3_free(aOut);
          return TCL_ERROR;
        }
        aOut = aNew;
        nAlloc = nNew;
      }
      nOut += putFts3Varint((char*)&aOut[nOut], iVal);
    }else{
      Tcl_Size nVal = 0;
      char *zVal = Tcl_GetStringFromObj(aArg[i], &nVal);
      while( (nOut + nVal)>nAlloc ){
        sqlite3_int64 nNew = nAlloc?nAlloc*2:128;
        unsigned char *aNew = sqlite3_realloc64(aOut, nNew);
        if( aNew==0 ){
          sqlite3_free(aOut);
          return TCL_ERROR;
        }
        aOut = aNew;
        nAlloc = nNew;
      }
Changes to src/test_init.c.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
**      of those subsystems that were initialized, and
**   3) A subsequent call to sqlite3_initialize() attempts to initialize
**      the remaining, uninitialized, subsystems.
*/

#include "sqliteInt.h"
#include <string.h>
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

static struct Wrapped {
  sqlite3_pcache_methods2 pcache;
  sqlite3_mem_methods     mem;
  sqlite3_mutex_methods   mutex;

  int mem_init;              /* True if mem subsystem is initialized */







<
<
<
|
<







23
24
25
26
27
28
29



30

31
32
33
34
35
36
37
**      of those subsystems that were initialized, and
**   3) A subsequent call to sqlite3_initialize() attempts to initialize
**      the remaining, uninitialized, subsystems.
*/

#include "sqliteInt.h"
#include <string.h>



#include "tclsqlite.h"


static struct Wrapped {
  sqlite3_pcache_methods2 pcache;
  sqlite3_mem_methods     mem;
  sqlite3_mutex_methods   mutex;

  int mem_init;              /* True if mem subsystem is initialized */
Changes to src/test_intarray.c.
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
}


/*****************************************************************************
** Everything below is interface for testing this module.
*/
#ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

/*
** Routines to encode and decode pointers
*/
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
extern void *sqlite3TestTextToPtr(const char*);
extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*);







<
<
<
|
<
<
<
<







275
276
277
278
279
280
281



282




283
284
285
286
287
288
289
}


/*****************************************************************************
** Everything below is interface for testing this module.
*/
#ifdef SQLITE_TEST



#include "tclsqlite.h"





/*
** Routines to encode and decode pointers
*/
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
extern void *sqlite3TestTextToPtr(const char*);
extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*);
Changes to src/test_malloc.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**
*************************************************************************
**
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>

/*
** This structure is used to encapsulate the global state variables used 
** by malloc() fault simulation.







<
<
<
|
<







10
11
12
13
14
15
16



17

18
19
20
21
22
23
24
**
*************************************************************************
**
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

/*
** This structure is used to encapsulate the global state variables used 
** by malloc() fault simulation.
383
384
385
386
387
388
389
390

391
392
393
394
395
396
397
static int SQLITE_TCLAPI test_memset(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  void *p;
  int size, n, i;

  char *zHex;
  char *zOut;
  char zBin[100];

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
    return TCL_ERROR;







|
>







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
static int SQLITE_TCLAPI test_memset(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  void *p;
  int size, i;
  Tcl_Size n;
  char *zHex;
  char *zOut;
  char zBin[100];

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
    return TCL_ERROR;
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  }
  if( size<=0 ){
    Tcl_AppendResult(interp, "size must be positive", (char*)0);
    return TCL_ERROR;
  }
  zHex = Tcl_GetStringFromObj(objv[3], &n);
  if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
  n = sqlite3TestHexToBin(zHex, n, zBin);
  if( n==0 ){
    Tcl_AppendResult(interp, "no data", (char*)0);
    return TCL_ERROR;
  }
  zOut = p;
  for(i=0; i<size; i++){
    zOut[i] = zBin[i%n];







|







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  }
  if( size<=0 ){
    Tcl_AppendResult(interp, "size must be positive", (char*)0);
    return TCL_ERROR;
  }
  zHex = Tcl_GetStringFromObj(objv[3], &n);
  if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
  n = sqlite3TestHexToBin(zHex, (int)n, zBin);
  if( n==0 ){
    Tcl_AppendResult(interp, "no data", (char*)0);
    return TCL_ERROR;
  }
  zOut = p;
  for(i=0; i<size; i++){
    zOut[i] = zBin[i%n];
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;

  for(ii=2; ii<objc; ii+=2){
    int nOption;
    char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
    char *zErr = 0;

    if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
      if( ii==(objc-1) ){
        zErr = "option requires an argument: ";
      }else{







|







617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;

  for(ii=2; ii<objc; ii+=2){
    Tcl_Size nOption;
    char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
    char *zErr = 0;

    if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
      if( ii==(objc-1) ){
        zErr = "option requires an argument: ";
      }else{
Changes to src/test_md5.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**
** This file contains code to implement an MD5 extension to TCL.
*/
#include "sqlite3.h"
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
#  define SQLITE_TCLAPI
# endif
#endif

/*
 * This code implements the MD5 message-digest algorithm.
 * The algorithm is due to Ron Rivest.  This code was
 * written by Colin Plumb in 1993, no copyright is claimed.
 * This code is in the public domain; do with it what you wish.
 *







<
<
<
|
<
<
<
<







12
13
14
15
16
17
18



19




20
21
22
23
24
25
26
**
** This file contains code to implement an MD5 extension to TCL.
*/
#include "sqlite3.h"
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"



#include "tclsqlite.h"





/*
 * This code implements the MD5 message-digest algorithm.
 * The algorithm is due to Ron Rivest.  This code was
 * written by Colin Plumb in 1993, no copyright is claimed.
 * This code is in the public domain; do with it what you wish.
 *
Changes to src/test_multiplex.c.
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
  memset(&gMultiplex, 0, sizeof(gMultiplex));
  return rc;
}

/***************************** Test Code ***********************************/
#ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif
extern const char *sqlite3ErrName(int);


/*
** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT
*/
static int SQLITE_TCLAPI test_multiplex_initialize(







<
<
<
|
<
<
<
<







1215
1216
1217
1218
1219
1220
1221



1222




1223
1224
1225
1226
1227
1228
1229
  sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
  memset(&gMultiplex, 0, sizeof(gMultiplex));
  return rc;
}

/***************************** Test Code ***********************************/
#ifdef SQLITE_TEST



#include "tclsqlite.h"




extern const char *sqlite3ErrName(int);


/*
** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT
*/
static int SQLITE_TCLAPI test_multiplex_initialize(
Changes to src/test_mutex.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
** 2008 June 18
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains test logic for the sqlite3_mutex interfaces.
*/

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#define MAX_MUTEXES        (SQLITE_MUTEX_STATIC_VFS3+1)













<
<
<
<
|
<







1
2
3
4
5
6
7
8
9
10
11
12
13




14

15
16
17
18
19
20
21
/*
** 2008 June 18
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains test logic for the sqlite3_mutex interfaces.
*/




#include "tclsqlite.h"

#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#define MAX_MUTEXES        (SQLITE_MUTEX_STATIC_VFS3+1)
Changes to src/test_osinst.c.
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
/**************************************************************************
***************************************************************************
** Tcl interface starts here.
*/

#if defined(SQLITE_TEST) || defined(TCLSH)

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

static int SQLITE_TCLAPI test_vfslog(
  void *clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){







<
<
<
|
<
<
<
<







1105
1106
1107
1108
1109
1110
1111



1112




1113
1114
1115
1116
1117
1118
1119
/**************************************************************************
***************************************************************************
** Tcl interface starts here.
*/

#if defined(SQLITE_TEST) || defined(TCLSH)




#include "tclsqlite.h"





static int SQLITE_TCLAPI test_vfslog(
  void *clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
Changes to src/test_quota.c.
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
  quotaLeave();
  sqlite3_free(zFull);
  return rc;
}

/***************************** Test Code ***********************************/
#ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

/*
** Argument passed to a TCL quota-over-limit callback.
*/
typedef struct TclQuotaCallback TclQuotaCallback;
struct TclQuotaCallback {
  Tcl_Interp *interp;    /* Interpreter in which to run the script */







<
<
<
|
<
<
<
<







1274
1275
1276
1277
1278
1279
1280



1281




1282
1283
1284
1285
1286
1287
1288
  quotaLeave();
  sqlite3_free(zFull);
  return rc;
}

/***************************** Test Code ***********************************/
#ifdef SQLITE_TEST



#include "tclsqlite.h"





/*
** Argument passed to a TCL quota-over-limit callback.
*/
typedef struct TclQuotaCallback TclQuotaCallback;
struct TclQuotaCallback {
  Tcl_Interp *interp;    /* Interpreter in which to run the script */
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
  Tcl_Obj *CONST objv[]
){
  const char *zPattern;           /* File pattern to configure */
  Tcl_WideInt iLimit;             /* Initial quota in bytes */
  Tcl_Obj *pScript;               /* Tcl script to invoke to increase quota */
  int rc;                         /* Value returned by quota_set() */
  TclQuotaCallback *p;            /* Callback object */
  int nScript;                    /* Length of callback script */
  void (*xDestroy)(void*);        /* Optional destructor for pArg */
  void (*xCallback)(const char *, sqlite3_int64 *, sqlite3_int64, void *);

  /* Process arguments */
  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "PATTERN LIMIT SCRIPT");
    return TCL_ERROR;







|







1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
  Tcl_Obj *CONST objv[]
){
  const char *zPattern;           /* File pattern to configure */
  Tcl_WideInt iLimit;             /* Initial quota in bytes */
  Tcl_Obj *pScript;               /* Tcl script to invoke to increase quota */
  int rc;                         /* Value returned by quota_set() */
  TclQuotaCallback *p;            /* Callback object */
  Tcl_Size nScript;               /* Length of callback script */
  void (*xDestroy)(void*);        /* Optional destructor for pArg */
  void (*xCallback)(const char *, sqlite3_int64 *, sqlite3_int64, void *);

  /* Process arguments */
  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "PATTERN LIMIT SCRIPT");
    return TCL_ERROR;
Changes to src/test_rtree.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"

#ifdef SQLITE_ENABLE_RTREE
/* 
** Type used to cache parameter information for the "circle" r-tree geometry







<
<
<
|
<







10
11
12
13
14
15
16



17

18
19
20
21
22
23
24
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"



#include "tclsqlite.h"


/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"

#ifdef SQLITE_ENABLE_RTREE
/* 
** Type used to cache parameter information for the "circle" r-tree geometry
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
}

/* END of implementation of "circle" geometry callback.
**************************************************************************
*************************************************************************/

#include <assert.h>
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

typedef struct Cube Cube;
struct Cube {
  double x;
  double y;
  double z;
  double width;







<
<
<
|
<







349
350
351
352
353
354
355



356

357
358
359
360
361
362
363
}

/* END of implementation of "circle" geometry callback.
**************************************************************************
*************************************************************************/

#include <assert.h>



#include "tclsqlite.h"


typedef struct Cube Cube;
struct Cube {
  double x;
  double y;
  double z;
  double width;
Changes to src/test_schema.c.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

/* If SQLITE_TEST is defined this code is preprocessed for use as part
** of the sqlite test binary "testfixture". Otherwise it is preprocessed
** to be compiled into an sqlite dynamic extension.
*/
#ifdef SQLITE_TEST
#  include "sqliteInt.h"
#  if defined(INCLUDE_SQLITE_TCL_H)
#    include "sqlite_tcl.h"
#  else
#    include "tcl.h"
#  endif
#else
#  include "sqlite3ext.h"
  SQLITE_EXTENSION_INIT1
#endif

#include <stdlib.h>
#include <string.h>







<
<
<
|
<







32
33
34
35
36
37
38



39

40
41
42
43
44
45
46

/* If SQLITE_TEST is defined this code is preprocessed for use as part
** of the sqlite test binary "testfixture". Otherwise it is preprocessed
** to be compiled into an sqlite dynamic extension.
*/
#ifdef SQLITE_TEST
#  include "sqliteInt.h"



#  include "tclsqlite.h"

#else
#  include "sqlite3ext.h"
  SQLITE_EXTENSION_INIT1
#endif

#include <stdlib.h>
#include <string.h>
Changes to src/test_superlock.c.
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
**************************************************************************
**************************************************************************
*************************************************************************/


#ifdef SQLITE_TEST

#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif

struct InterpAndScript {
  Tcl_Interp *interp;
  Tcl_Obj *pScript;
};
typedef struct InterpAndScript InterpAndScript;








<
<
<
|
<
<
<
<







252
253
254
255
256
257
258



259




260
261
262
263
264
265
266
**************************************************************************
**************************************************************************
*************************************************************************/


#ifdef SQLITE_TEST




#include "tclsqlite.h"





struct InterpAndScript {
  Tcl_Interp *interp;
  Tcl_Obj *pScript;
};
typedef struct InterpAndScript InterpAndScript;

Changes to src/test_syscall.c.
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
**     If PGSZ is a power of two greater than 256, install a wrapper around
**     OS function getpagesize() that reports the system page size as PGSZ.
**     Or, if PGSZ is less than zero, remove any wrapper already installed.
*/

#include "sqliteInt.h"
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#if SQLITE_OS_UNIX

/* From main.c */







<
<
<
|
<







72
73
74
75
76
77
78



79

80
81
82
83
84
85
86
**     If PGSZ is a power of two greater than 256, install a wrapper around
**     OS function getpagesize() that reports the system page size as PGSZ.
**     Or, if PGSZ is less than zero, remove any wrapper already installed.
*/

#include "sqliteInt.h"
#include "sqlite3.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#if SQLITE_OS_UNIX

/* From main.c */
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
**
** Usually, the current error-number is the value that errno should be set
** to if the named system call fails. The exception is "fallocate". See 
** comments above the implementation of ts_fallocate() for details.
*/
static int tsErrno(const char *zFunc){
  int i;
  int nFunc = strlen(zFunc);
  for(i=0; aSyscall[i].zName; i++){
    if( strlen(aSyscall[i].zName)!=nFunc ) continue;
    if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
    return aSyscall[i].custom_errno;
  }

  assert(0);







|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
**
** Usually, the current error-number is the value that errno should be set
** to if the named system call fails. The exception is "fallocate". See 
** comments above the implementation of ts_fallocate() for details.
*/
static int tsErrno(const char *zFunc){
  int i;
  size_t nFunc = strlen(zFunc);
  for(i=0; aSyscall[i].zName; i++){
    if( strlen(aSyscall[i].zName)!=nFunc ) continue;
    if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
    return aSyscall[i].custom_errno;
  }

  assert(0);
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
static int SQLITE_TCLAPI test_syscall_install(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_vfs *pVfs; 
  int nElem;
  int i;
  Tcl_Obj **apElem;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL-LIST");
    return TCL_ERROR;
  }
  if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
    return TCL_ERROR;
  }
  pVfs = sqlite3_vfs_find(0);

  for(i=0; i<nElem; i++){
    int iCall;
    int rc = Tcl_GetIndexFromObjStruct(interp, 
        apElem[i], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
    );
    if( rc ) return rc;
    if( aSyscall[iCall].xOrig==0 ){
      aSyscall[iCall].xOrig = pVfs->xGetSystemCall(pVfs, aSyscall[iCall].zName);







|












|







421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
static int SQLITE_TCLAPI test_syscall_install(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_vfs *pVfs; 
  Tcl_Size nElem;
  int i;
  Tcl_Obj **apElem;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL-LIST");
    return TCL_ERROR;
  }
  if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
    return TCL_ERROR;
  }
  pVfs = sqlite3_vfs_find(0);

  for(i=0; i<(int)nElem; i++){
    int iCall;
    int rc = Tcl_GetIndexFromObjStruct(interp, 
        apElem[i], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
    );
    if( rc ) return rc;
    if( aSyscall[iCall].xOrig==0 ){
      aSyscall[iCall].xOrig = pVfs->xGetSystemCall(pVfs, aSyscall[iCall].zName);
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  }

  pVfs = sqlite3_vfs_find(0);
  if( objc==2 ){
    rc = pVfs->xSetSystemCall(pVfs, 0, 0);
    for(i=0; aSyscall[i].zName; i++) aSyscall[i].xOrig = 0;
  }else{
    int nFunc;
    char *zFunc = Tcl_GetStringFromObj(objv[2], &nFunc);
    rc = pVfs->xSetSystemCall(pVfs, Tcl_GetString(objv[2]), 0);
    for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){
      if( strlen(aSyscall[i].zName)!=nFunc ) continue;
      if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
      aSyscall[i].xOrig = 0;
    }







|







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
  }

  pVfs = sqlite3_vfs_find(0);
  if( objc==2 ){
    rc = pVfs->xSetSystemCall(pVfs, 0, 0);
    for(i=0; aSyscall[i].zName; i++) aSyscall[i].xOrig = 0;
  }else{
    Tcl_Size nFunc;
    char *zFunc = Tcl_GetStringFromObj(objv[2], &nFunc);
    rc = pVfs->xSetSystemCall(pVfs, Tcl_GetString(objv[2]), 0);
    for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){
      if( strlen(aSyscall[i].zName)!=nFunc ) continue;
      if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
      aSyscall[i].xOrig = 0;
    }
Changes to src/test_tclsh.c.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
** "testfixture.exe") using logic encoded by this file.
**
** The code in this file used to be found in tclsqlite3.c, contained within
** #if SQLITE_TEST ... #endif.  It is factored out into this separate module
** in an effort to keep the tclsqlite.c file pure.
*/
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
#  define SQLITE_TCLAPI
# endif
#endif

/* Needed for the setrlimit() system call on unix */
#if defined(unix)
#include <sys/resource.h>
#endif

/* Forward declaration */







<
<
<
|
<
<
<
<







16
17
18
19
20
21
22



23




24
25
26
27
28
29
30
** "testfixture.exe") using logic encoded by this file.
**
** The code in this file used to be found in tclsqlite3.c, contained within
** #if SQLITE_TEST ... #endif.  It is factored out into this separate module
** in an effort to keep the tclsqlite.c file pure.
*/
#include "sqlite3.h"



#include "tclsqlite.h"





/* Needed for the setrlimit() system call on unix */
#if defined(unix)
#include <sys/resource.h>
#endif

/* Forward declaration */
Changes to src/test_tclvar.c.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
**
** For SELECT operations, the "name" and "arrayname" fields will always
** match the "fullname" field.  For DELETE, INSERT, and UPDATE, the
** "name" and "arrayname" fields are ignored and the variable is modified
** according to "fullname" and "value" only.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

/*
** Characters that make up the idxStr created by xBestIndex for xFilter.







<
<
<
|
<







32
33
34
35
36
37
38



39

40
41
42
43
44
45
46
**
** For SELECT operations, the "name" and "arrayname" fields will always
** match the "fullname" field.  For DELETE, INSERT, and UPDATE, the
** "name" and "arrayname" fields are ignored and the variable is modified
** according to "fullname" and "value" only.
*/
#include "sqliteInt.h"



#include "tclsqlite.h"

#include <stdlib.h>
#include <string.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

/*
** Characters that make up the idxStr created by xBestIndex for xFilter.
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

/* A tclvar cursor object */
struct tclvar_cursor {
  sqlite3_vtab_cursor base;

  Tcl_Obj *pList1;     /* Result of [info vars ?pattern?] */
  Tcl_Obj *pList2;     /* Result of [array names [lindex $pList1 $i1]] */
  int i1;              /* Current item in pList1 */
  int i2;              /* Current item (if any) in pList2 */
};

/* Methods for the tclvar module */
static int tclvarConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,







|
|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

/* A tclvar cursor object */
struct tclvar_cursor {
  sqlite3_vtab_cursor base;

  Tcl_Obj *pList1;     /* Result of [info vars ?pattern?] */
  Tcl_Obj *pList2;     /* Result of [array names [lindex $pList1 $i1]] */
  Tcl_Size i1;              /* Current item in pList1 */
  Tcl_Size i2;              /* Current item (if any) in pList2 */
};

/* Methods for the tclvar module */
static int tclvarConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
      Tcl_ListObjAppendElement(0, p, pObj);
      Tcl_EvalObjEx(interp, p, TCL_EVAL_GLOBAL);
      Tcl_DecrRefCount(p);
      pCur->pList2 = Tcl_GetObjResult(interp);
      Tcl_IncrRefCount(pCur->pList2);
      assert( pCur->i2==0 );
    }else{
      int n = 0;
      pCur->i2++;
      Tcl_ListObjLength(0, pCur->pList2, &n);
      if( pCur->i2>=n ){
        Tcl_DecrRefCount(pCur->pList2);
        pCur->pList2 = 0;
        pCur->i2 = 0;
        return 0;
      }
    }
  }

  return 1;
}

static int tclvarNext(sqlite3_vtab_cursor *cur){
  Tcl_Obj *pObj;
  int n = 0;
  int ok = 0;

  tclvar_cursor *pCur = (tclvar_cursor *)cur;
  Tcl_Interp *interp = ((tclvar_vtab *)(cur->pVtab))->interp;

  Tcl_ListObjLength(0, pCur->pList1, &n);
  while( !ok && pCur->i1<n ){







|
















|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
      Tcl_ListObjAppendElement(0, p, pObj);
      Tcl_EvalObjEx(interp, p, TCL_EVAL_GLOBAL);
      Tcl_DecrRefCount(p);
      pCur->pList2 = Tcl_GetObjResult(interp);
      Tcl_IncrRefCount(pCur->pList2);
      assert( pCur->i2==0 );
    }else{
      Tcl_Size n = 0;
      pCur->i2++;
      Tcl_ListObjLength(0, pCur->pList2, &n);
      if( pCur->i2>=n ){
        Tcl_DecrRefCount(pCur->pList2);
        pCur->pList2 = 0;
        pCur->i2 = 0;
        return 0;
      }
    }
  }

  return 1;
}

static int tclvarNext(sqlite3_vtab_cursor *cur){
  Tcl_Obj *pObj;
  Tcl_Size n = 0;
  int ok = 0;

  tclvar_cursor *pCur = (tclvar_cursor *)cur;
  Tcl_Interp *interp = ((tclvar_vtab *)(cur->pVtab))->interp;

  Tcl_ListObjLength(0, pCur->pList1, &n);
  while( !ok && pCur->i1<n ){
Changes to src/test_thread.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
**
** This file contains the implementation of some Tcl commands used to
** test that sqlite3 database handles may be concurrently accessed by 
** multiple threads. Right now this only works on unix.
*/

#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

#if SQLITE_THREADSAFE

#include <errno.h>

#if !defined(_MSC_VER)
#include <unistd.h>







<
<
<
|
<







12
13
14
15
16
17
18



19

20
21
22
23
24
25
26
**
** This file contains the implementation of some Tcl commands used to
** test that sqlite3 database handles may be concurrently accessed by 
** multiple threads. Right now this only works on unix.
*/

#include "sqliteInt.h"



#include "tclsqlite.h"


#if SQLITE_THREADSAFE

#include <errno.h>

#if !defined(_MSC_VER)
#include <unistd.h>
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
** Register an EvalEvent to evaluate the script pScript in the
** parent interpreter/thread of SqlThread p.
*/
static void postToParent(SqlThread *p, Tcl_Obj *pScript){
  EvalEvent *pEvent;
  char *zMsg;
  int nMsg;

  zMsg = Tcl_GetStringFromObj(pScript, &nMsg); 
  pEvent = (EvalEvent *)ckalloc(sizeof(EvalEvent)+nMsg+1);
  pEvent->base.nextPtr = 0;
  pEvent->base.proc = tclScriptEvent;
  pEvent->zScript = (char *)&pEvent[1];
  memcpy(pEvent->zScript, zMsg, nMsg+1);







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
** Register an EvalEvent to evaluate the script pScript in the
** parent interpreter/thread of SqlThread p.
*/
static void postToParent(SqlThread *p, Tcl_Obj *pScript){
  EvalEvent *pEvent;
  char *zMsg;
  Tcl_Size nMsg;

  zMsg = Tcl_GetStringFromObj(pScript, &nMsg); 
  pEvent = (EvalEvent *)ckalloc(sizeof(EvalEvent)+nMsg+1);
  pEvent->base.nextPtr = 0;
  pEvent->base.proc = tclScriptEvent;
  pEvent->zScript = (char *)&pEvent[1];
  memcpy(pEvent->zScript, zMsg, nMsg+1);
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_ThreadId x;
  SqlThread *pNew;
  int rc;

  int nVarname; char *zVarname;
  int nScript; char *zScript;

  /* Parameters for thread creation */
  const int nStack = TCL_THREAD_STACK_DEFAULT;
  const int flags = TCL_THREAD_NOFLAGS;

  assert(objc==4);
  UNUSED_PARAMETER(clientData);







|
|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_ThreadId x;
  SqlThread *pNew;
  int rc;

  Tcl_Size nVarname; char *zVarname;
  Tcl_Size nScript; char *zScript;

  /* Parameters for thread creation */
  const int nStack = TCL_THREAD_STACK_DEFAULT;
  const int flags = TCL_THREAD_NOFLAGS;

  assert(objc==4);
  UNUSED_PARAMETER(clientData);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  ClientData clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  EvalEvent *pEvent;
  char *zMsg;
  int nMsg;
  SqlThread *p = (SqlThread *)clientData;

  assert(objc==3);
  UNUSED_PARAMETER(objc);

  if( p==0 ){
    Tcl_AppendResult(interp, "no parent thread", 0);







|







224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  ClientData clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  EvalEvent *pEvent;
  char *zMsg;
  Tcl_Size nMsg;
  SqlThread *p = (SqlThread *)clientData;

  assert(objc==3);
  UNUSED_PARAMETER(objc);

  if( p==0 ){
    Tcl_AppendResult(interp, "no parent thread", 0);
Changes to src/test_vdbecov.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
******************************************************************************
**
*/
#if SQLITE_TEST          /* This file is used for testing only */

#include "sqlite3.h"
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

#ifdef SQLITE_VDBE_COVERAGE

static u8 aBranchArray[200000];

static void test_vdbe_branch(
  void *pCtx, 







<
<
<
|
<







11
12
13
14
15
16
17



18

19
20
21
22
23
24
25
******************************************************************************
**
*/
#if SQLITE_TEST          /* This file is used for testing only */

#include "sqlite3.h"
#include "sqliteInt.h"



#include "tclsqlite.h"


#ifdef SQLITE_VDBE_COVERAGE

static u8 aBranchArray[200000];

static void test_vdbe_branch(
  void *pCtx, 
Changes to src/test_vfs.c.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
**   -mxpathname INTEGER        (Value for sqlite3_vfs.mxPathname)
**   -iversion   INTEGER        (Value for sqlite3_vfs.iVersion)
*/
#if SQLITE_TEST          /* This file is used for testing only */

#include "sqlite3.h"
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
#  include "sqlite_tcl.h"
#else
#  include "tcl.h"
#endif

typedef struct Testvfs Testvfs;
typedef struct TestvfsShm TestvfsShm;
typedef struct TestvfsBuffer TestvfsBuffer;
typedef struct TestvfsFile TestvfsFile;
typedef struct TestvfsFd TestvfsFd;








<
<
<
|
<







24
25
26
27
28
29
30



31

32
33
34
35
36
37
38
**   -mxpathname INTEGER        (Value for sqlite3_vfs.mxPathname)
**   -iversion   INTEGER        (Value for sqlite3_vfs.iVersion)
*/
#if SQLITE_TEST          /* This file is used for testing only */

#include "sqlite3.h"
#include "sqliteInt.h"



#include "tclsqlite.h"


typedef struct Testvfs Testvfs;
typedef struct TestvfsShm TestvfsShm;
typedef struct TestvfsBuffer TestvfsBuffer;
typedef struct TestvfsFile TestvfsFile;
typedef struct TestvfsFd TestvfsFd;

1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
      }
      ckfree(zName);
      if( !pBuffer ){
        Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), 0);
        return TCL_ERROR;
      }
      if( objc==4 ){
        int n;
        u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n);
        int pgsz = pBuffer->pgsz;
        if( pgsz==0 ) pgsz = 65536;
        for(i=0; i*pgsz<n; i++){
          int nByte = pgsz;
          tvfsAllocPage(pBuffer, i, pgsz);
          if( n-i*pgsz<pgsz ){
            nByte = n;
          }
          memcpy(pBuffer->aPage[i], &a[i*pgsz], nByte);
        }
      }

      pObj = Tcl_NewObj();
      for(i=0; pBuffer->aPage[i]; i++){







|



|



|







1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
      }
      ckfree(zName);
      if( !pBuffer ){
        Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), 0);
        return TCL_ERROR;
      }
      if( objc==4 ){
        Tcl_Size n;
        u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n);
        int pgsz = pBuffer->pgsz;
        if( pgsz==0 ) pgsz = 65536;
        for(i=0; i*pgsz<(int)n; i++){
          int nByte = pgsz;
          tvfsAllocPage(pBuffer, i, pgsz);
          if( n-i*pgsz<pgsz ){
            nByte = (int)n;
          }
          memcpy(pBuffer->aPage[i], &a[i*pgsz], nByte);
        }
      }

      pObj = Tcl_NewObj();
      for(i=0; pBuffer->aPage[i]; i++){
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
        { "xFullPathname",      TESTVFS_FULLPATHNAME_MASK },
        { "xUnlock",            TESTVFS_UNLOCK_MASK },
        { "xLock",              TESTVFS_LOCK_MASK },
        { "xCheckReservedLock", TESTVFS_CKLOCK_MASK },
        { "xFileControl",       TESTVFS_FCNTL_MASK },
      };
      Tcl_Obj **apElem = 0;
      int nElem = 0;
      int mask = 0;
      if( objc!=3 ){
        Tcl_WrongNumArgs(interp, 2, objv, "LIST");
        return TCL_ERROR;
      }
      if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
        return TCL_ERROR;
      }
      Tcl_ResetResult(interp);
      for(i=0; i<nElem; i++){
        int iMethod;
        char *zElem = Tcl_GetString(apElem[i]);
        for(iMethod=0; iMethod<ArraySize(vfsmethod); iMethod++){
          if( strcmp(zElem, vfsmethod[iMethod].zName)==0 ){
            mask |= vfsmethod[iMethod].mask;
            break;
          }







|









|







1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
        { "xFullPathname",      TESTVFS_FULLPATHNAME_MASK },
        { "xUnlock",            TESTVFS_UNLOCK_MASK },
        { "xLock",              TESTVFS_LOCK_MASK },
        { "xCheckReservedLock", TESTVFS_CKLOCK_MASK },
        { "xFileControl",       TESTVFS_FCNTL_MASK },
      };
      Tcl_Obj **apElem = 0;
      Tcl_Size nElem = 0;
      int mask = 0;
      if( objc!=3 ){
        Tcl_WrongNumArgs(interp, 2, objv, "LIST");
        return TCL_ERROR;
      }
      if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
        return TCL_ERROR;
      }
      Tcl_ResetResult(interp);
      for(i=0; i<(int)nElem; i++){
        int iMethod;
        char *zElem = Tcl_GetString(apElem[i]);
        for(iMethod=0; iMethod<ArraySize(vfsmethod); iMethod++){
          if( strcmp(zElem, vfsmethod[iMethod].zName)==0 ){
            mask |= vfsmethod[iMethod].mask;
            break;
          }
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
    **  TESTVFS script ?SCRIPT?
    **
    **  Query or set the script to be run when filtered VFS events
    **  occur.
    */
    case CMD_SCRIPT: {
      if( objc==3 ){
        int nByte;
        if( p->pScript ){
          Tcl_DecrRefCount(p->pScript);
          p->pScript = 0;
        }
        Tcl_GetStringFromObj(objv[2], &nByte);
        if( nByte>0 ){
          p->pScript = Tcl_DuplicateObj(objv[2]);







|







1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
    **  TESTVFS script ?SCRIPT?
    **
    **  Query or set the script to be run when filtered VFS events
    **  occur.
    */
    case CMD_SCRIPT: {
      if( objc==3 ){
        Tcl_Size nByte;
        if( p->pScript ){
          Tcl_DecrRefCount(p->pScript);
          p->pScript = 0;
        }
        Tcl_GetStringFromObj(objv[2], &nByte);
        if( nByte>0 ){
          p->pScript = Tcl_DuplicateObj(objv[2]);
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
        Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?");
        return TCL_ERROR;
      }
      if( objc==3 ){
        int j;
        int iNew = 0;
        Tcl_Obj **flags = 0;
        int nFlags = 0;

        if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){
          return TCL_ERROR;
        }

        for(j=0; j<nFlags; j++){
          int idx = 0;
          if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag, 
                sizeof(aFlag[0]), "flag", 0, &idx) 
          ){
            return TCL_ERROR;
          }
          if( aFlag[idx].iValue<0 && nFlags>1 ){







|





|







1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
        Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?");
        return TCL_ERROR;
      }
      if( objc==3 ){
        int j;
        int iNew = 0;
        Tcl_Obj **flags = 0;
        Tcl_Size nFlags = 0;

        if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){
          return TCL_ERROR;
        }

        for(j=0; j<(int)nFlags; j++){
          int idx = 0;
          if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag, 
                sizeof(aFlag[0]), "flag", 0, &idx) 
          ){
            return TCL_ERROR;
          }
          if( aFlag[idx].iValue<0 && nFlags>1 ){
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
  int isDefault = 0;              /* True if -default is passed */
  int szOsFile = 0;               /* Value passed to -szosfile */
  int mxPathname = -1;            /* Value passed to -mxpathname */
  int iVersion = 3;               /* Value passed to -iversion */

  if( objc<2 || 0!=(objc%2) ) goto bad_args;
  for(i=2; i<objc; i += 2){
    int nSwitch;
    char *zSwitch;
    zSwitch = Tcl_GetStringFromObj(objv[i], &nSwitch); 

    if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){
      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isNoshm) ){
        return TCL_ERROR;
      }







|







1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
  int isDefault = 0;              /* True if -default is passed */
  int szOsFile = 0;               /* Value passed to -szosfile */
  int mxPathname = -1;            /* Value passed to -mxpathname */
  int iVersion = 3;               /* Value passed to -iversion */

  if( objc<2 || 0!=(objc%2) ) goto bad_args;
  for(i=2; i<objc; i += 2){
    Tcl_Size nSwitch;
    char *zSwitch;
    zSwitch = Tcl_GetStringFromObj(objv[i], &nSwitch); 

    if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){
      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isNoshm) ){
        return TCL_ERROR;
      }
Changes to src/test_window.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
*/

#include "sqlite3.h"

#ifdef SQLITE_TEST

#include "sqliteInt.h"
#include <tcl.h>

extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
extern const char *sqlite3ErrName(int);

typedef struct TestWindow TestWindow;
struct TestWindow {
  Tcl_Obj *xStep;







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
*/

#include "sqlite3.h"

#ifdef SQLITE_TEST

#include "sqliteInt.h"
#include "tclsqlite.h"

extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
extern const char *sqlite3ErrName(int);

typedef struct TestWindow TestWindow;
struct TestWindow {
  Tcl_Obj *xStep;
Changes to src/vdbesort.c.
552
553
554
555
556
557
558
559
560
561
562
563
564
565

566
567
568
569
570
571
572
    nRem = nByte - nAvail;

    /* The following loop copies up to p->nBuffer bytes per iteration into
    ** the p->aAlloc[] buffer.  */
    while( nRem>0 ){
      int rc;                     /* vdbePmaReadBlob() return code */
      int nCopy;                  /* Number of bytes to copy */
      u8 *aNext;                  /* Pointer to buffer to copy data from */

      nCopy = nRem;
      if( nRem>p->nBuffer ) nCopy = p->nBuffer;
      rc = vdbePmaReadBlob(p, nCopy, &aNext);
      if( rc!=SQLITE_OK ) return rc;
      assert( aNext!=p->aAlloc );

      memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy);
      nRem -= nCopy;
    }

    *ppOut = p->aAlloc;
  }








|






>







552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    nRem = nByte - nAvail;

    /* The following loop copies up to p->nBuffer bytes per iteration into
    ** the p->aAlloc[] buffer.  */
    while( nRem>0 ){
      int rc;                     /* vdbePmaReadBlob() return code */
      int nCopy;                  /* Number of bytes to copy */
      u8 *aNext = 0;              /* Pointer to buffer to copy data from */

      nCopy = nRem;
      if( nRem>p->nBuffer ) nCopy = p->nBuffer;
      rc = vdbePmaReadBlob(p, nCopy, &aNext);
      if( rc!=SQLITE_OK ) return rc;
      assert( aNext!=p->aAlloc );
      assert( aNext!=0 );
      memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy);
      nRem -= nCopy;
    }

    *ppOut = p->aAlloc;
  }

Changes to src/where.c.
1497
1498
1499
1500
1501
1502
1503













1504
1505
1506
1507
1508
1509
1510
  pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
  pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm];
  pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
  pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
  pIdxInfo->aConstraint = pIdxCons;
  pIdxInfo->aOrderBy = pIdxOrderBy;
  pIdxInfo->aConstraintUsage = pUsage;













  pHidden->pWC = pWC;
  pHidden->pParse = pParse;
  pHidden->eDistinct = eDistinct;
  pHidden->mIn = 0;
  for(p=pWC, i=j=0; p; p=p->pOuter){
    int nLast = i+p->nTerm;;
    for(pTerm=p->a; i<nLast; i++, pTerm++){







>
>
>
>
>
>
>
>
>
>
>
>
>







1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
  pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
  pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm];
  pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
  pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
  pIdxInfo->aConstraint = pIdxCons;
  pIdxInfo->aOrderBy = pIdxOrderBy;
  pIdxInfo->aConstraintUsage = pUsage;
  pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
  if( HasRowid(pTab)==0 ){
    /* Ensure that all bits associated with PK columns are set. This is to
    ** ensure they are available for cases like RIGHT joins or OR loops. */
    Index *pPk = sqlite3PrimaryKeyIndex((Table*)pTab);
    assert( pPk!=0 );
    for(i=0; i<pPk->nKeyCol; i++){
      int iCol = pPk->aiColumn[i];
      assert( iCol>=0 );
      if( iCol>=BMS-1 ) iCol = BMS-1;
      pIdxInfo->colUsed |= MASKBIT(iCol);
    }
  }
  pHidden->pWC = pWC;
  pHidden->pParse = pParse;
  pHidden->eDistinct = eDistinct;
  pHidden->mIn = 0;
  for(p=pWC, i=j=0; p; p=p->pOuter){
    int nLast = i+p->nTerm;;
    for(pTerm=p->a; i<nLast; i++, pTerm++){
4030
4031
4032
4033
4034
4035
4036
4037


4038
4039
4040
4041
4042
4043
4044
            }else{
              assert( isCov==WHERE_EXPRIDX );
              WHERETRACE(0x200,
                 ("-> %s might be a covering expression index"
                  " according to whereIsCoveringIndex()\n", pProbe->zName));
            }
          }
        }else if( m==0 ){


          WHERETRACE(0x200,
             ("-> %s a covering index according to bitmasks\n",
             pProbe->zName, m==0 ? "is" : "is not"));
          pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
        }
      }








|
>
>







4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
            }else{
              assert( isCov==WHERE_EXPRIDX );
              WHERETRACE(0x200,
                 ("-> %s might be a covering expression index"
                  " according to whereIsCoveringIndex()\n", pProbe->zName));
            }
          }
        }else if( m==0 
           && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700))
        ){
          WHERETRACE(0x200,
             ("-> %s a covering index according to bitmasks\n",
             pProbe->zName, m==0 ? "is" : "is not"));
          pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
        }
      }

4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
  assert( pIdxInfo->needToFreeIdxStr==0 );
  pIdxInfo->idxStr = 0;
  pIdxInfo->idxNum = 0;
  pIdxInfo->orderByConsumed = 0;
  pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
  pIdxInfo->estimatedRows = 25;
  pIdxInfo->idxFlags = 0;
  pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
  pHidden->mHandleIn = 0;

  /* Invoke the virtual table xBestIndex() method */
  rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
  if( rc ){
    if( rc==SQLITE_CONSTRAINT ){
      /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means







<







4227
4228
4229
4230
4231
4232
4233

4234
4235
4236
4237
4238
4239
4240
  assert( pIdxInfo->needToFreeIdxStr==0 );
  pIdxInfo->idxStr = 0;
  pIdxInfo->idxNum = 0;
  pIdxInfo->orderByConsumed = 0;
  pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
  pIdxInfo->estimatedRows = 25;
  pIdxInfo->idxFlags = 0;

  pHidden->mHandleIn = 0;

  /* Invoke the virtual table xBestIndex() method */
  rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
  if( rc ){
    if( rc==SQLITE_CONSTRAINT ){
      /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
    VdbeOp *pOp
  ){
    if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
    sqlite3VdbePrintOp(0, pc, pOp);
  }
#endif

#ifdef SQLITE_DEBUG
/*
** Return true if cursor iCur is opened by instruction k of the
** bytecode.  Used inside of assert() only.
*/
static int cursorIsOpen(Vdbe *v, int iCur, int k){
  while( k>=0 ){
    VdbeOp *pOp = sqlite3VdbeGetOp(v,k--);
    if( pOp->p1!=iCur ) continue;
    if( pOp->opcode==OP_Close ) return 0;
    if( pOp->opcode==OP_OpenRead ) return 1;
    if( pOp->opcode==OP_OpenWrite ) return 1;
    if( pOp->opcode==OP_OpenDup ) return 1;
    if( pOp->opcode==OP_OpenAutoindex ) return 1;
    if( pOp->opcode==OP_OpenEphemeral ) return 1;
  }
  return 0;
}
#endif /* SQLITE_DEBUG */

/*
** Generate the end of the WHERE loop.  See comments on
** sqlite3WhereBegin() for additional information.
*/
void sqlite3WhereEnd(WhereInfo *pWInfo){
  Parse *pParse = pWInfo->pParse;
  Vdbe *v = pParse->pVdbe;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







7076
7077
7078
7079
7080
7081
7082




















7083
7084
7085
7086
7087
7088
7089
    VdbeOp *pOp
  ){
    if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
    sqlite3VdbePrintOp(0, pc, pOp);
  }
#endif





















/*
** Generate the end of the WHERE loop.  See comments on
** sqlite3WhereBegin() for additional information.
*/
void sqlite3WhereEnd(WhereInfo *pWInfo){
  Parse *pParse = pWInfo->pParse;
  Vdbe *v = pParse->pVdbe;
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392

7393
7394
7395
7396
7397

7398
7399
7400
7401
7402
7403
7404
            pOp->p1 = pLevel->iIdxCur;
            OpcodeRewriteTrace(db, k, pOp);
          }else{
            /* Unable to translate the table reference into an index
            ** reference.  Verify that this is harmless - that the
            ** table being referenced really is open.
            */
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
            assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
                 || cursorIsOpen(v,pOp->p1,k)
                 || pOp->opcode==OP_Offset
            );

#else
            assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
                 || cursorIsOpen(v,pOp->p1,k)
            );
#endif

          }
        }else if( pOp->opcode==OP_Rowid ){
          pOp->p1 = pLevel->iIdxCur;
          pOp->opcode = OP_IdxRowid;
          OpcodeRewriteTrace(db, k, pOp);
        }else if( pOp->opcode==OP_IfNullRow ){
          pOp->p1 = pLevel->iIdxCur;







<
|
<
<
<
>
|
<
<
<
<
>







7375
7376
7377
7378
7379
7380
7381

7382



7383
7384




7385
7386
7387
7388
7389
7390
7391
7392
            pOp->p1 = pLevel->iIdxCur;
            OpcodeRewriteTrace(db, k, pOp);
          }else{
            /* Unable to translate the table reference into an index
            ** reference.  Verify that this is harmless - that the
            ** table being referenced really is open.
            */

            if( pLoop->wsFlags & WHERE_IDX_ONLY ){



              sqlite3ErrorMsg(pParse, "internal query planner error");
              pParse->rc = SQLITE_INTERNAL;




            }
          }
        }else if( pOp->opcode==OP_Rowid ){
          pOp->p1 = pLevel->iIdxCur;
          pOp->opcode = OP_IdxRowid;
          OpcodeRewriteTrace(db, k, pOp);
        }else if( pOp->opcode==OP_IfNullRow ){
          pOp->p1 = pLevel->iIdxCur;
Changes to test/backcompat.test.
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  }
}

proc read_file {zFile} {
  set zData {}
  if {[file exists $zFile]} {
    set fd [open $zFile]
    fconfigure $fd -translation binary -encoding binary

    if {[file size $zFile]<=$::sqlite_pending_byte || $zFile != "test.db"} {
      set zData [read $fd]
    } else {
      set zData [read $fd $::sqlite_pending_byte]
      append zData [string repeat x 512]
      seek $fd [expr $::sqlite_pending_byte+512] start
      append zData [read $fd]
    }

    close $fd
  }
  return $zData
}
proc write_file {zFile zData} {
  set fd [open $zFile w]
  fconfigure $fd -translation binary -encoding binary
  puts -nonewline $fd $zData
  close $fd
}
proc read_file_system {} {
  set ret [list]
  foreach f {test.db test.db-journal test.db-wal} { lappend ret [read_file $f] }
  set ret







|
















|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  }
}

proc read_file {zFile} {
  set zData {}
  if {[file exists $zFile]} {
    set fd [open $zFile]
    fconfigure $fd -translation binary

    if {[file size $zFile]<=$::sqlite_pending_byte || $zFile != "test.db"} {
      set zData [read $fd]
    } else {
      set zData [read $fd $::sqlite_pending_byte]
      append zData [string repeat x 512]
      seek $fd [expr $::sqlite_pending_byte+512] start
      append zData [read $fd]
    }

    close $fd
  }
  return $zData
}
proc write_file {zFile zData} {
  set fd [open $zFile w]
  fconfigure $fd -translation binary
  puts -nonewline $fd $zData
  close $fd
}
proc read_file_system {} {
  set ret [list]
  foreach f {test.db test.db-journal test.db-wal} { lappend ret [read_file $f] }
  set ret
Added test/bestindexD.test.


























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# 2024-08-03
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# 
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix bestindexD

ifcapable !vtab {
  finish_test
  return
}

register_tcl_module db

proc vtab_command {method args} {
  switch -- $method {
    xConnect {
      return "CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID"
    }

    xBestIndex {
      set hdl [lindex $args 0]
      set ::colUsed [$hdl mask]

      set cost 1000000
      set used ""

      set cons 0
      foreach c [$hdl constraints] {
        set cost [expr $cost/10]
        append used " use $cons"
        incr cons
      }

      return "cost $cost rows $cost $used"
    }
  }

  return {}
}

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);

  CREATE TABLE t2(a, b);
} {}

# This proc assumes that there is only one use of a virtual table - x1 -
# in SQL statement $sql. It tests that the colUsed value passed to the
# xBestIndex method matches the actual columns used, which is ascertained 
# by searching the compiled VM code for VColumn instructions.
#
proc do_colsused_test {tn sql} {
  set ::colUsed ""
  execsql $sql
  set got $::colUsed

  set expect 0
  db eval "EXPLAIN $sql" x {
    if {$x(opcode)=="VColumn"} {
      set expect [expr $expect | (1<<$x(p2))]
    }
  }

  uplevel [list do_test $tn.($expect/$got) [list expr ($expect & $got)] $expect]
}

do_colsused_test 1.1 { SELECT a FROM x1 }   
do_colsused_test 1.2 { SELECT a,c FROM x1 } 
do_colsused_test 1.3 { SELECT b FROM x1 }   
do_colsused_test 1.4 { SELECT b FROM x1 WHERE c=? } 

do_colsused_test 1.5 {
  select 1 from t2 full join x1;
}

do_colsused_test 1.6 {
  select 1 from x1 WHERE (b=? AND c=?) OR (b=? AND c=?)
}

finish_test


Changes to test/cast.test.
230
231
232
233
234
235
236

237
238
239
240
241
242
243
#
do_test cast-3.1 {
  execsql {SELECT CAST(9223372036854774800 AS integer)}
} 9223372036854774800
do_test cast-3.2 {
  execsql {SELECT CAST(9223372036854774800 AS numeric)}
} 9223372036854774800

do_realnum_test cast-3.3 {
  execsql {SELECT CAST(9223372036854774800 AS real)}
} 9.22337203685477e+18
do_test cast-3.4 {
  execsql {SELECT CAST(CAST(9223372036854774800 AS real) AS integer)}
} 9223372036854774784
do_test cast-3.5 {







>







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#
do_test cast-3.1 {
  execsql {SELECT CAST(9223372036854774800 AS integer)}
} 9223372036854774800
do_test cast-3.2 {
  execsql {SELECT CAST(9223372036854774800 AS numeric)}
} 9223372036854774800
breakpoint
do_realnum_test cast-3.3 {
  execsql {SELECT CAST(9223372036854774800 AS real)}
} 9.22337203685477e+18
do_test cast-3.4 {
  execsql {SELECT CAST(CAST(9223372036854774800 AS real) AS integer)}
} 9223372036854774784
do_test cast-3.5 {
Changes to test/corrupt.test.
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  # to run. After copying the contents of the root page to the new child,
  # btreeInitPage() is called on the child. This time, it detects corruption
  # (because the start of the blob associated with the (rowid=10) record
  # no longer looks like a real cell). At one point the code assumed that 
  # detecting corruption was not possible at that point, and an assert() failed.
  #
  set fd [open test.db r+]
  fconfigure $fd -translation binary -encoding binary
  seek $fd [expr 1024+8]
  puts -nonewline $fd "\x03\x14"
  close $fd
  
  sqlite3 db test.db
  do_test corrupt-7.2 {
    execsql { 







|







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  # to run. After copying the contents of the root page to the new child,
  # btreeInitPage() is called on the child. This time, it detects corruption
  # (because the start of the blob associated with the (rowid=10) record
  # no longer looks like a real cell). At one point the code assumed that 
  # detecting corruption was not possible at that point, and an assert() failed.
  #
  set fd [open test.db r+]
  fconfigure $fd -translation binary
  seek $fd [expr 1024+8]
  puts -nonewline $fd "\x03\x14"
  close $fd
  
  sqlite3 db test.db
  do_test corrupt-7.2 {
    execsql { 
Changes to test/corrupt2.test.
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  db2 close

  # Corrupt the page-size (bytes 16 and 17 of page 1).
  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db
  set f [open corrupt.db RDWR]
  fconfigure $f -encoding binary
  seek $f 16 start
  puts -nonewline $f "\x00\xFF"
  close $f

  sqlite3 db2 corrupt.db
  catchsql "
    $::presql
    SELECT * FROM sqlite_master;
  " db2
} {1 {file is not a database}}

do_test corrupt2-1.4 {
  db2 close

  # Corrupt the free-block list on page 1.
  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db
  set f [open corrupt.db RDWR]
  fconfigure $f -encoding binary
  seek $f 101 start
  puts -nonewline $f "\xFF\xFF"
  close $f

  sqlite3 db2 corrupt.db
  # Note: This test is no longer meaningful due to the deferred computation
  # of MemPage.nFree 
  catchsql {PRAGMA quick_check} db2
} {0 {{*** in database main ***
Tree 1 page 1: free space corruption}}}

do_test corrupt2-1.5 {
  db2 close

  # Corrupt the free-block list on page 1.
  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db
  set f [open corrupt.db RDWR]
  fconfigure $f -encoding binary
  seek $f 101 start
  puts -nonewline $f "\x00\xC8"
  seek $f 200 start
  puts -nonewline $f "\x00\x00"
  puts -nonewline $f "\x10\x00"
  close $f








|



















|



















|







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  db2 close

  # Corrupt the page-size (bytes 16 and 17 of page 1).
  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db
  set f [open corrupt.db RDWR]
  fconfigure $f -translation binary
  seek $f 16 start
  puts -nonewline $f "\x00\xFF"
  close $f

  sqlite3 db2 corrupt.db
  catchsql "
    $::presql
    SELECT * FROM sqlite_master;
  " db2
} {1 {file is not a database}}

do_test corrupt2-1.4 {
  db2 close

  # Corrupt the free-block list on page 1.
  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db
  set f [open corrupt.db RDWR]
  fconfigure $f -translation binary
  seek $f 101 start
  puts -nonewline $f "\xFF\xFF"
  close $f

  sqlite3 db2 corrupt.db
  # Note: This test is no longer meaningful due to the deferred computation
  # of MemPage.nFree 
  catchsql {PRAGMA quick_check} db2
} {0 {{*** in database main ***
Tree 1 page 1: free space corruption}}}

do_test corrupt2-1.5 {
  db2 close

  # Corrupt the free-block list on page 1.
  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db
  set f [open corrupt.db RDWR]
  fconfigure $f -translation binary
  seek $f 101 start
  puts -nonewline $f "\x00\xC8"
  seek $f 200 start
  puts -nonewline $f "\x00\x00"
  puts -nonewline $f "\x10\x00"
  close $f

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

  # On the root page of table t2 (page 4), set one of the child page-numbers
  # to 0. This corruption will be detected when SQLite attempts to update
  # the pointer-map after moving the content of page 4 to page 3 as part
  # of the DROP TABLE operation below.
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -encoding binary -translation binary
  seek $fd [expr 1024*3 + 12]
  set zCelloffset [read $fd 2]
  binary scan $zCelloffset S iCelloffset
  seek $fd [expr 1024*3 + $iCelloffset]
  puts -nonewline $fd "\00\00\00\00" 
  close $fd








|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

  # On the root page of table t2 (page 4), set one of the child page-numbers
  # to 0. This corruption will be detected when SQLite attempts to update
  # the pointer-map after moving the content of page 4 to page 3 as part
  # of the DROP TABLE operation below.
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary
  seek $fd [expr 1024*3 + 12]
  set zCelloffset [read $fd 2]
  binary scan $zCelloffset S iCelloffset
  seek $fd [expr 1024*3 + $iCelloffset]
  puts -nonewline $fd "\00\00\00\00" 
  close $fd

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  " db2

  db2 close

  # This block links a page from table t2 into the t1 table structure.
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -encoding binary -translation binary
  seek $fd [expr 1024 + 12]
  set zCelloffset [read $fd 2]
  binary scan $zCelloffset S iCelloffset
  seek $fd [expr 1024 + $iCelloffset]
  set zChildPage [read $fd 4]
  seek $fd [expr 2*1024 + 12]
  set zCelloffset [read $fd 2]







|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  " db2

  db2 close

  # This block links a page from table t2 into the t1 table structure.
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary
  seek $fd [expr 1024 + 12]
  set zCelloffset [read $fd 2]
  binary scan $zCelloffset S iCelloffset
  seek $fd [expr 1024 + $iCelloffset]
  set zChildPage [read $fd 4]
  seek $fd [expr 2*1024 + 12]
  set zCelloffset [read $fd 2]
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
}

corruption_test -sqlprep $sqlprep -corrupt {
  # Set the page-flags of one of the leaf pages of the index B-Tree to
  # 0x0D (interpreted by SQLite as "leaf page of a table B-Tree").
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary -encoding binary
  seek $fd [expr 1024*2 + 8] 
  set zRightChild [read $fd 4]
  binary scan $zRightChild I iRightChild
  seek $fd [expr 1024*($iRightChild-1)]
  puts -nonewline $fd "\x0D"
  close $fd
} -test {
  do_test corrupt2-7.1 {
    catchsql " $::presql SELECT b FROM t1 ORDER BY b ASC "
  } {1 {database disk image is malformed}}
}

corruption_test -sqlprep $sqlprep -corrupt {
  # Mess up the page-header of one of the leaf pages of the index B-Tree.
  # The corruption is detected as part of an OP_Prev opcode.
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary -encoding binary
  seek $fd [expr 1024*2 + 12] 
  set zCellOffset [read $fd 2]
  binary scan $zCellOffset S iCellOffset
  seek $fd [expr 1024*2 + $iCellOffset]
  set zChild [read $fd 4]
  binary scan $zChild I iChild
  seek $fd [expr 1024*($iChild-1)+3]
  puts -nonewline $fd "\xFFFF"
  close $fd
} -test {
  do_test corrupt2-7.1 {
    catchsql " $::presql SELECT b FROM t1 ORDER BY b DESC "
  } {1 {database disk image is malformed}}
}

corruption_test -sqlprep $sqlprep -corrupt {
  # Set the page-flags of one of the leaf pages of the table B-Tree to
  # 0x0A (interpreted by SQLite as "leaf page of an index B-Tree").
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary -encoding binary
  seek $fd [expr 1024*1 + 8] 
  set zRightChild [read $fd 4]
  binary scan $zRightChild I iRightChild
  seek $fd [expr 1024*($iRightChild-1)]
  puts -nonewline $fd "\x0A"
  close $fd
} -test {







|

















|




















|







388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
}

corruption_test -sqlprep $sqlprep -corrupt {
  # Set the page-flags of one of the leaf pages of the index B-Tree to
  # 0x0D (interpreted by SQLite as "leaf page of a table B-Tree").
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary
  seek $fd [expr 1024*2 + 8] 
  set zRightChild [read $fd 4]
  binary scan $zRightChild I iRightChild
  seek $fd [expr 1024*($iRightChild-1)]
  puts -nonewline $fd "\x0D"
  close $fd
} -test {
  do_test corrupt2-7.1 {
    catchsql " $::presql SELECT b FROM t1 ORDER BY b ASC "
  } {1 {database disk image is malformed}}
}

corruption_test -sqlprep $sqlprep -corrupt {
  # Mess up the page-header of one of the leaf pages of the index B-Tree.
  # The corruption is detected as part of an OP_Prev opcode.
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary
  seek $fd [expr 1024*2 + 12] 
  set zCellOffset [read $fd 2]
  binary scan $zCellOffset S iCellOffset
  seek $fd [expr 1024*2 + $iCellOffset]
  set zChild [read $fd 4]
  binary scan $zChild I iChild
  seek $fd [expr 1024*($iChild-1)+3]
  puts -nonewline $fd "\xFFFF"
  close $fd
} -test {
  do_test corrupt2-7.1 {
    catchsql " $::presql SELECT b FROM t1 ORDER BY b DESC "
  } {1 {database disk image is malformed}}
}

corruption_test -sqlprep $sqlprep -corrupt {
  # Set the page-flags of one of the leaf pages of the table B-Tree to
  # 0x0A (interpreted by SQLite as "leaf page of an index B-Tree").
  #
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary
  seek $fd [expr 1024*1 + 8] 
  set zRightChild [read $fd 4]
  binary scan $zRightChild I iRightChild
  seek $fd [expr 1024*($iRightChild-1)]
  puts -nonewline $fd "\x0A"
  close $fd
} -test {
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  CREATE TABLE x2(a, b, c); CREATE TABLE x9(a, b, c); CREATE TABLE xF(a, b, c);
  CREATE TABLE x3(a, b, c); CREATE TABLE xA(a, b, c); CREATE TABLE xG(a, b, c);
  CREATE TABLE x4(a, b, c); CREATE TABLE xB(a, b, c); CREATE TABLE xH(a, b, c);
  CREATE TABLE x5(a, b, c); CREATE TABLE xC(a, b, c); CREATE TABLE xI(a, b, c);
  CREATE TABLE x6(a, b, c); CREATE TABLE xD(a, b, c); CREATE TABLE xJ(a, b, c);
} -corrupt {
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary -encoding binary
  seek $fd 108
  set zRightChild [read $fd 4]
  binary scan $zRightChild I iRightChild
  seek $fd [expr 1024*($iRightChild-1)+3]
  puts -nonewline $fd "\x00\x00"
  close $fd
} -test {







|







455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  CREATE TABLE x2(a, b, c); CREATE TABLE x9(a, b, c); CREATE TABLE xF(a, b, c);
  CREATE TABLE x3(a, b, c); CREATE TABLE xA(a, b, c); CREATE TABLE xG(a, b, c);
  CREATE TABLE x4(a, b, c); CREATE TABLE xB(a, b, c); CREATE TABLE xH(a, b, c);
  CREATE TABLE x5(a, b, c); CREATE TABLE xC(a, b, c); CREATE TABLE xI(a, b, c);
  CREATE TABLE x6(a, b, c); CREATE TABLE xD(a, b, c); CREATE TABLE xJ(a, b, c);
} -corrupt {
  set fd [open corrupt.db r+]
  fconfigure $fd -translation binary
  seek $fd 108
  set zRightChild [read $fd 4]
  binary scan $zRightChild I iRightChild
  seek $fd [expr 1024*($iRightChild-1)+3]
  puts -nonewline $fd "\x00\x00"
  close $fd
} -test {
Changes to test/corrupt4.test.
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  puts -nonewline $fd $bin
}

# Page 1 is now the grandparent of its leaves. Corrupt the database by setting 
# the second rightmost child page number of page 1 to 1.
#
set fd [open test.db r+]
fconfigure $fd -encoding binary -translation binary
set nChild [get2byte $fd 103]
set offChild [get2byte $fd [expr 100+12+($nChild-2)*2]]
set pgnoChild [get4byte $fd $offChild]
put4byte $fd $offChild 1
close $fd

if {![info exists ::G(perm:presql)]} {







|







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  puts -nonewline $fd $bin
}

# Page 1 is now the grandparent of its leaves. Corrupt the database by setting 
# the second rightmost child page number of page 1 to 1.
#
set fd [open test.db r+]
fconfigure $fd -translation binary
set nChild [get2byte $fd 103]
set offChild [get2byte $fd [expr 100+12+($nChild-2)*2]]
set pgnoChild [get4byte $fd $offChild]
put4byte $fd $offChild 1
close $fd

if {![info exists ::G(perm:presql)]} {
Changes to test/corruptK.test.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
do_test 1.2 {
  db close
  hexio_write test.db [expr 1024 + 0x360] 21
  hexio_write test.db [expr 1024 + 0x363] [format %x [expr 31*2 + 12]]
  sqlite3 db test.db

  set fd [db incrblob t1 x 3]
  fconfigure $fd -translation binary -encoding binary
  seek $fd 30
  puts -nonewline $fd "\x18"
  close $fd
} {}
do_execsql_test 1.3 {
  INSERT INTO t1 VALUES(randomblob(20));
}







|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
do_test 1.2 {
  db close
  hexio_write test.db [expr 1024 + 0x360] 21
  hexio_write test.db [expr 1024 + 0x363] [format %x [expr 31*2 + 12]]
  sqlite3 db test.db

  set fd [db incrblob t1 x 3]
  fconfigure $fd -translation binary
  seek $fd 30
  puts -nonewline $fd "\x18"
  close $fd
} {}
do_execsql_test 1.3 {
  INSERT INTO t1 VALUES(randomblob(20));
}
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
do_test 2.2 {
  db close
  hexio_write test.db [expr 1024 + 0x388] 53
  hexio_write test.db [expr 1024 + 0x38A] 03812C

  sqlite3 db test.db
  set fd [db incrblob t1 x 5]
  fconfigure $fd -translation binary -encoding binary

  seek $fd 22
  puts -nonewline $fd "\x5d"
  close $fd
} {}

do_catchsql_test 2.3 {







|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
do_test 2.2 {
  db close
  hexio_write test.db [expr 1024 + 0x388] 53
  hexio_write test.db [expr 1024 + 0x38A] 03812C

  sqlite3 db test.db
  set fd [db incrblob t1 x 5]
  fconfigure $fd -translation binary

  seek $fd 22
  puts -nonewline $fd "\x5d"
  close $fd
} {}

do_catchsql_test 2.3 {
Changes to test/crash.test.
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);
    INSERT INTO abc2 VALUES(randstr(1500,1500), 0, 0);
    COMMIT;
  }

  # Change the checksum value for the master journal name.
  set f [open test.db-journal a]
  fconfigure $f -encoding binary
  seek $f [expr [file size test.db-journal] - 12]
  puts -nonewline $f "\00\00\00\00"
  close $f
} {}
do_test crash-7.2 {
  signature
} $sig







|







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);
    INSERT INTO abc2 VALUES(randstr(1500,1500), 0, 0);
    COMMIT;
  }

  # Change the checksum value for the master journal name.
  set f [open test.db-journal a]
  fconfigure $f -translation binary
  seek $f [expr [file size test.db-journal] - 12]
  puts -nonewline $f "\00\00\00\00"
  close $f
} {}
do_test crash-7.2 {
  signature
} $sig
Changes to test/exclusive2.test.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# moments.  So disable the soft-heap-limit.
#
sqlite3_soft_heap_limit 0

proc pagerChangeCounter {filename new {fd ""}} {
  if {$fd==""} {
    set fd [open $filename RDWR]
    fconfigure $fd -translation binary -encoding binary
    set needClose 1
  } else {
    set needClose 0
  }
  if {$new ne ""} {
    seek $fd 24
    set a [expr {($new&0xFF000000)>>24}]







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# moments.  So disable the soft-heap-limit.
#
sqlite3_soft_heap_limit 0

proc pagerChangeCounter {filename new {fd ""}} {
  if {$fd==""} {
    set fd [open $filename RDWR]
    fconfigure $fd -translation binary
    set needClose 1
  } else {
    set needClose 0
  }
  if {$new ne ""} {
    seek $fd 24
    set a [expr {($new&0xFF000000)>>24}]
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

  if {$needClose} {close $fd}
  return $ret
}

proc readPagerChangeCounter {filename} {
  set fd [open $filename RDONLY]
  fconfigure $fd -translation binary -encoding binary

  seek $fd 24
  foreach {a b c d} [list 0 0 0 0] {}
  binary scan [read $fd 4] cccc a b c d
  set  ret [expr ($a&0x000000FF)<<24]
  incr ret [expr ($b&0x000000FF)<<16]
  incr ret [expr ($c&0x000000FF)<<8]







|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

  if {$needClose} {close $fd}
  return $ret
}

proc readPagerChangeCounter {filename} {
  set fd [open $filename RDONLY]
  fconfigure $fd -translation binary

  seek $fd 24
  foreach {a b c d} [list 0 0 0 0] {}
  binary scan [read $fd 4] cccc a b c d
  set  ret [expr ($a&0x000000FF)<<24]
  incr ret [expr ($b&0x000000FF)<<16]
  incr ret [expr ($c&0x000000FF)<<8]
Changes to test/fts3snippet.test.
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571

do_test 4.3 {
  llength [db one {
    SELECT snippet(t4, '', '', '', 0, 150) FROM t4 WHERE t4 MATCH 'E'
  }]
} {64}


#-------------------------------------------------------------------------
# Request a snippet from a query with more than 64 phrases.
#
do_execsql_test 5.0 {
  CREATE VIRTUAL TABLE t5 USING fts3(x);
  INSERT INTO t5 VALUES('a1 a2 a3');
  INSERT INTO t5 VALUES('a4 a5 a6');







<







557
558
559
560
561
562
563

564
565
566
567
568
569
570

do_test 4.3 {
  llength [db one {
    SELECT snippet(t4, '', '', '', 0, 150) FROM t4 WHERE t4 MATCH 'E'
  }]
} {64}


#-------------------------------------------------------------------------
# Request a snippet from a query with more than 64 phrases.
#
do_execsql_test 5.0 {
  CREATE VIRTUAL TABLE t5 USING fts3(x);
  INSERT INTO t5 VALUES('a1 a2 a3');
  INSERT INTO t5 VALUES('a4 a5 a6');
583
584
585
586
587
588
589




590
591
592
  'a61 OR a62 OR a63 OR a64 OR a65 OR a66 OR a67 OR a68 OR a69 OR a60 OR ' ||
  'a71 OR a72 OR a73 OR a74 OR a75 OR a76 OR a77 OR a78 OR a79 OR a70'
} {
  {[a1] [a2] [a3]}
  {[a4] [a5] [a6]}
  {[a70] [a71] [a72]}
}





set sqlite_fts3_enable_parentheses 0
finish_test







>
>
>
>



582
583
584
585
586
587
588
589
590
591
592
593
594
595
  'a61 OR a62 OR a63 OR a64 OR a65 OR a66 OR a67 OR a68 OR a69 OR a60 OR ' ||
  'a71 OR a72 OR a73 OR a74 OR a75 OR a76 OR a77 OR a78 OR a79 OR a70'
} {
  {[a1] [a2] [a3]}
  {[a4] [a5] [a6]}
  {[a70] [a71] [a72]}
}

do_execsql_test 5.2 {
  SELECT snippet(t5, '[', ']', -1, 0) FROM t5 WHERE t5 MATCH 'a5'
} {{a4 [a5] a6}}

set sqlite_fts3_enable_parentheses 0
finish_test
Changes to test/func6.test.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  INSERT INTO t2(x,y) SELECT a, b FROM t1;
}

# Load the contents of $file from disk and return it encoded as a hex
# string.
proc loadhex {file} {
  set fd [open $file]
  fconfigure $fd -translation binary -encoding binary
  set data [read $fd]
  close $fd
  binary encode hex $data 
}

# Each argument is either an integer between 0 and 65535, a text value, or
# an empty string representing an SQL NULL. This command builds an SQLite







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  INSERT INTO t2(x,y) SELECT a, b FROM t1;
}

# Load the contents of $file from disk and return it encoded as a hex
# string.
proc loadhex {file} {
  set fd [open $file]
  fconfigure $fd -translation binary
  set data [read $fd]
  close $fd
  binary encode hex $data 
}

# Each argument is either an integer between 0 and 65535, a text value, or
# an empty string representing an SQL NULL. This command builds an SQLite
Changes to test/func7.test.
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
do_execsql_test func7-pg-280 {
   SELECT trunc(42.8), trunc(-42.8);
} {42.0 -42.0}
do_execsql_test func7-pg-300 {
   SELECT acos(1);
} {0.0}
do_execsql_test func7-pg-301 {
   SELECT degrees(acos(0.5));
} {60.0}
do_execsql_test func7-pg-310 {
   SELECT round( asin(1), 7);
} {1.5707963}
do_execsql_test func7-pg-311 {
   SELECT degrees( asin(0.5) );
} {30.0}
do_execsql_test func7-pg-320 {
   SELECT round( atan(1), 7);
} {0.7853982}
do_execsql_test func7-pg-321 {
   SELECT degrees( atan(1) );
} {45.0}







|





|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
do_execsql_test func7-pg-280 {
   SELECT trunc(42.8), trunc(-42.8);
} {42.0 -42.0}
do_execsql_test func7-pg-300 {
   SELECT acos(1);
} {0.0}
do_execsql_test func7-pg-301 {
   SELECT format('%f',degrees(acos(0.5)));
} {60.0}
do_execsql_test func7-pg-310 {
   SELECT round( asin(1), 7);
} {1.5707963}
do_execsql_test func7-pg-311 {
   SELECT format('%f',degrees( asin(0.5) ));
} {30.0}
do_execsql_test func7-pg-320 {
   SELECT round( atan(1), 7);
} {0.7853982}
do_execsql_test func7-pg-321 {
   SELECT degrees( atan(1) );
} {45.0}
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
do_execsql_test func7-pg-411 {
   SELECT sin( radians(30) );
} {0.5}
do_execsql_test func7-pg-420 {
   SELECT round( tan(1), 7);
} {1.5574077}
do_execsql_test func7-pg-421 {
   SELECT tan( radians(45) );
} {1.0}
do_execsql_test func7-pg-500 {
   SELECT round( sinh(1), 7);
} {1.1752012}
do_execsql_test func7-pg-510 {
   SELECT round( cosh(0), 7);
} {1.0}







|







135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
do_execsql_test func7-pg-411 {
   SELECT sin( radians(30) );
} {0.5}
do_execsql_test func7-pg-420 {
   SELECT round( tan(1), 7);
} {1.5574077}
do_execsql_test func7-pg-421 {
   SELECT round(tan( radians(45) ),10);
} {1.0}
do_execsql_test func7-pg-500 {
   SELECT round( sinh(1), 7);
} {1.1752012}
do_execsql_test func7-pg-510 {
   SELECT round( cosh(0), 7);
} {1.0}
Changes to test/fuzz3.test.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# command (assuming that the file is at least ($x>>8) bytes in size).
#
proc modify_database {iMod} {
  set blob [binary format c [expr {$iMod&0xFF}]]
  set offset [expr {$iMod>>8}]

  set fd [open test.db r+]
  fconfigure $fd -encoding binary -translation binary
  seek $fd $offset
  set old_blob [read $fd 1]
  seek $fd $offset
  puts -nonewline $fd $blob
  close $fd

  binary scan $old_blob c iOld







|







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# command (assuming that the file is at least ($x>>8) bytes in size).
#
proc modify_database {iMod} {
  set blob [binary format c [expr {$iMod&0xFF}]]
  set offset [expr {$iMod>>8}]

  set fd [open test.db r+]
  fconfigure $fd -translation binary
  seek $fd $offset
  set old_blob [read $fd 1]
  seek $fd $offset
  puts -nonewline $fd $blob
  close $fd

  binary scan $old_blob c iOld
Changes to test/fuzzinvariants.c.
33
34
35
36
37
38
39

























40
41
42
43
44
45
46
static void reportInvariantFailed(
  sqlite3_stmt *pOrig,   /* The original query */
  sqlite3_stmt *pTest,   /* The alternative test query with a missing row */
  int iRow,              /* Row number in pOrig */
  unsigned int dbOpt,    /* Optimization flags on pOrig */
  int noOpt              /* True if opt flags inverted for pTest */
);


























/*
** Do an invariant check on pStmt.  iCnt determines which invariant check to
** perform.  The first check is iCnt==0.
**
** *pbCorrupt is a flag that, if true, indicates that the database file
** is known to be corrupt.  A value of non-zero means "yes, the database







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
static void reportInvariantFailed(
  sqlite3_stmt *pOrig,   /* The original query */
  sqlite3_stmt *pTest,   /* The alternative test query with a missing row */
  int iRow,              /* Row number in pOrig */
  unsigned int dbOpt,    /* Optimization flags on pOrig */
  int noOpt              /* True if opt flags inverted for pTest */
);

/*
** Special parameter binding, for testing and debugging purposes.
**
**     $int_NNN      ->   integer value NNN
**     $text_TTTT    ->   floating point value TTT with destructor
*/
static void bindDebugParameters(sqlite3_stmt *pStmt){
  int nVar = sqlite3_bind_parameter_count(pStmt);
  int i;
  for(i=0; i<nVar; i++){
    const char *zVar = sqlite3_bind_parameter_name(pStmt, i+1);
    if( zVar==0 ) continue;
    if( strncmp(zVar, "$int_", 5)==0 ){
      sqlite3_bind_int(pStmt, i+1, atoi(&zVar[5]));
    }else
    if( strncmp(zVar, "$text_", 6)==0 ){
      char *zBuf = sqlite3_malloc64( strlen(zVar)-5 );
      if( zBuf ){
        memcpy(zBuf, &zVar[6], strlen(zVar)-5);
        sqlite3_bind_text64(pStmt, i+1, zBuf, -1, sqlite3_free, SQLITE_UTF8);
      }
    }
  }
}

/*
** Do an invariant check on pStmt.  iCnt determines which invariant check to
** perform.  The first check is iCnt==0.
**
** *pbCorrupt is a flag that, if true, indicates that the database file
** is known to be corrupt.  A value of non-zero means "yes, the database
103
104
105
106
107
108
109

110
111
112
113
114
115
116
             sqlite3_errmsg(db), zTest);
    }
    sqlite3_free(zTest);
    sqlite3_finalize(pTestStmt);
    return rc;
  }
  sqlite3_free(zTest);

  nCol = sqlite3_column_count(pStmt);
  for(i=0; i<nCol; i++){
    rc = sqlite3_bind_value(pTestStmt,i+1+nParam,sqlite3_column_value(pStmt,i));
    if( rc!=SQLITE_OK && rc!=SQLITE_RANGE ){
      sqlite3_finalize(pTestStmt);
      return rc;
    }







>







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
             sqlite3_errmsg(db), zTest);
    }
    sqlite3_free(zTest);
    sqlite3_finalize(pTestStmt);
    return rc;
  }
  sqlite3_free(zTest);
  bindDebugParameters(pTestStmt);
  nCol = sqlite3_column_count(pStmt);
  for(i=0; i<nCol; i++){
    rc = sqlite3_bind_value(pTestStmt,i+1+nParam,sqlite3_column_value(pStmt,i));
    if( rc!=SQLITE_OK && rc!=SQLITE_RANGE ){
      sqlite3_finalize(pTestStmt);
      return rc;
    }
167
168
169
170
171
172
173

174
175
176
177
178
179
180
    sqlite3_prepare_v2(db, sqlite3_sql(pStmt), -1, &pCk, 0);
    sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, iOrigRSO, 0);
    if( eVerbosity>=2 ){
      char *zSql = sqlite3_expanded_sql(pCk);
      printf("invariant-validity-check #2:\n%s\n", zSql);
      sqlite3_free(zSql);
    }

    while( (rc = sqlite3_step(pCk))==SQLITE_ROW ){
      for(i=0; i<nCol; i++){
        if( !sameValue(pStmt, i, pTestStmt, i, 0) ) break;
      }
      if( i>=nCol ) break;
    }
    sqlite3_finalize(pCk);







>







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
    sqlite3_prepare_v2(db, sqlite3_sql(pStmt), -1, &pCk, 0);
    sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, iOrigRSO, 0);
    if( eVerbosity>=2 ){
      char *zSql = sqlite3_expanded_sql(pCk);
      printf("invariant-validity-check #2:\n%s\n", zSql);
      sqlite3_free(zSql);
    }
    bindDebugParameters(pCk);
    while( (rc = sqlite3_step(pCk))==SQLITE_ROW ){
      for(i=0; i<nCol; i++){
        if( !sameValue(pStmt, i, pTestStmt, i, 0) ) break;
      }
      if( i>=nCol ) break;
    }
    sqlite3_finalize(pCk);
195
196
197
198
199
200
201

202
203
204
205
206
207
208
      if( eVerbosity>=2 ){
        char *zSql = sqlite3_expanded_sql(pCk);
        printf("invariant-validity-check #3:\n%s\n", zSql);
        sqlite3_free(zSql);
      }

      sqlite3_reset(pTestStmt);

      while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){
        for(i=0; i<nCol; i++){
          if( !sameValue(pStmt, i, pTestStmt, i, pCk) ) break;
        }
        if( i>=nCol ){
          sqlite3_finalize(pCk);
          goto not_a_fault;







>







222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
      if( eVerbosity>=2 ){
        char *zSql = sqlite3_expanded_sql(pCk);
        printf("invariant-validity-check #3:\n%s\n", zSql);
        sqlite3_free(zSql);
      }

      sqlite3_reset(pTestStmt);
      bindDebugParameters(pCk);
      while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){
        for(i=0; i<nCol; i++){
          if( !sameValue(pStmt, i, pTestStmt, i, pCk) ) break;
        }
        if( i>=nCol ){
          sqlite3_finalize(pCk);
          goto not_a_fault;
294
295
296
297
298
299
300

301
302
303
304
305
306
307
  sqlite3_str_append(pTest, zIn, (int)nIn);
  sqlite3_str_append(pTest, ")", 1);
  rc = sqlite3_prepare_v2(db, sqlite3_str_value(pTest), -1, &pBase, 0);
  if( rc ){
    sqlite3_finalize(pBase);
    pBase = pStmt;
  }

  for(i=0; i<sqlite3_column_count(pStmt); i++){
    const char *zColName = sqlite3_column_name(pBase,i);
    const char *zSuffix = zColName ? strrchr(zColName, ':') : 0;
    if( zSuffix 
     && isdigit(zSuffix[1])
     && (zSuffix[1]>'3' || isdigit(zSuffix[2]))
    ){







>







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  sqlite3_str_append(pTest, zIn, (int)nIn);
  sqlite3_str_append(pTest, ")", 1);
  rc = sqlite3_prepare_v2(db, sqlite3_str_value(pTest), -1, &pBase, 0);
  if( rc ){
    sqlite3_finalize(pBase);
    pBase = pStmt;
  }
  bindDebugParameters(pBase);
  for(i=0; i<sqlite3_column_count(pStmt); i++){
    const char *zColName = sqlite3_column_name(pBase,i);
    const char *zSuffix = zColName ? strrchr(zColName, ':') : 0;
    if( zSuffix 
     && isdigit(zSuffix[1])
     && (zSuffix[1]>'3' || isdigit(zSuffix[2]))
    ){
Changes to test/incrvacuum3.test.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  # Now copy the database file itself. Do this using open/read/puts
  # instead of the [file copy] command in order to avoid attempting
  # to read the 512 bytes begining at offset $sqlite_pending_byte.
  #
  set sz [file size test.db]
  set fd [open test.db]
  set fd2 [open test2.db w]
  fconfigure $fd  -encoding binary -translation binary
  fconfigure $fd2 -encoding binary -translation binary
  if {$sz>$::sqlite_pending_byte} {
    puts -nonewline $fd2 [read $fd $::sqlite_pending_byte]
    seek $fd [expr $::sqlite_pending_byte+512]
    seek $fd2 [expr $::sqlite_pending_byte+512]
  }
  puts -nonewline $fd2 [read $fd]
  close $fd2







|
|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  # Now copy the database file itself. Do this using open/read/puts
  # instead of the [file copy] command in order to avoid attempting
  # to read the 512 bytes begining at offset $sqlite_pending_byte.
  #
  set sz [file size test.db]
  set fd [open test.db]
  set fd2 [open test2.db w]
  fconfigure $fd  -translation binary
  fconfigure $fd2 -translation binary
  if {$sz>$::sqlite_pending_byte} {
    puts -nonewline $fd2 [read $fd $::sqlite_pending_byte]
    seek $fd [expr $::sqlite_pending_byte+512]
    seek $fd2 [expr $::sqlite_pending_byte+512]
  }
  puts -nonewline $fd2 [read $fd]
  close $fd2
Changes to test/ioerr.test.
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
    }
    forcecopy test.db-journal test2.db-journal
    execsql {
      COMMIT;
    }
    forcecopy test2.db-journal test.db-journal
    set f [open test.db-journal a]
    fconfigure $f -encoding binary
    puts -nonewline $f "hello"
    puts -nonewline $f "\x00\x00\x00\x05\x01\x02\x03\x04"
    puts -nonewline $f "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7"
    close $f
  } -sqlbody {
    SELECT a FROM t1;
  }







|







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
    }
    forcecopy test.db-journal test2.db-journal
    execsql {
      COMMIT;
    }
    forcecopy test2.db-journal test.db-journal
    set f [open test.db-journal a]
    fconfigure $f -translation binary
    puts -nonewline $f "hello"
    puts -nonewline $f "\x00\x00\x00\x05\x01\x02\x03\x04"
    puts -nonewline $f "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7"
    close $f
  } -sqlbody {
    SELECT a FROM t1;
  }
Changes to test/ioerr5.test.
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    set ::sqlite_io_error_hit 0
    set ::sqlite_io_error_persist 0
    set ::sqlite_io_error_pending 0
  
    # Read the contents of the database file into a Tcl variable.
    #
    set fd [open test.db]
    fconfigure $fd -translation binary -encoding binary
    set zDatabase [read $fd]
    close $fd

    # Set a very low soft-limit and then try to compile an SQL statement 
    # from UTF-16 text. To do this, SQLite will need to reclaim memory
    # from the pager that is in error state. Including that associated
    # with the dirty page.
    #
    do_test ioerr5-1.$locking_mode-$iFail.3 {
      sqlite3_soft_heap_limit 1024
      compilesql16 "SELECT 10"
    } {SQLITE_OK}

    close $channel

    # Ensure that nothing was written to the database while reclaiming
    # memory from the pager in error state.
    #
    do_test ioerr5-1.$locking_mode-$iFail.4 {
      set fd [open test.db]
      fconfigure $fd -translation binary -encoding binary
      set zDatabase2 [read $fd]
      close $fd
      expr {$zDatabase eq $zDatabase2}
    } {1}

    if {$rc eq [list 0 {}]} {
      do_test ioerr5.1-$locking_mode-$iFail.3 {







|




















|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    set ::sqlite_io_error_hit 0
    set ::sqlite_io_error_persist 0
    set ::sqlite_io_error_pending 0
  
    # Read the contents of the database file into a Tcl variable.
    #
    set fd [open test.db]
    fconfigure $fd -translation binary
    set zDatabase [read $fd]
    close $fd

    # Set a very low soft-limit and then try to compile an SQL statement 
    # from UTF-16 text. To do this, SQLite will need to reclaim memory
    # from the pager that is in error state. Including that associated
    # with the dirty page.
    #
    do_test ioerr5-1.$locking_mode-$iFail.3 {
      sqlite3_soft_heap_limit 1024
      compilesql16 "SELECT 10"
    } {SQLITE_OK}

    close $channel

    # Ensure that nothing was written to the database while reclaiming
    # memory from the pager in error state.
    #
    do_test ioerr5-1.$locking_mode-$iFail.4 {
      set fd [open test.db]
      fconfigure $fd -translation binary
      set zDatabase2 [read $fd]
      close $fd
      expr {$zDatabase eq $zDatabase2}
    } {1}

    if {$rc eq [list 0 {}]} {
      do_test ioerr5.1-$locking_mode-$iFail.3 {
Changes to test/memdb1.test.
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
    CREATE TABLE t1(x, y);
    INSERT INTO t1 VALUES(1, 2);
    CREATE TABLE t2(x, y);
  } {wal}
  db close
  
  set fd [open test.db]
  fconfigure $fd -translation binary -encoding binary
  set data [read $fd [expr 20*1024]]
  close $fd
  
  sqlite3 db ""
  db deserialize $data
  
  do_execsql_test 810 {







|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
    CREATE TABLE t1(x, y);
    INSERT INTO t1 VALUES(1, 2);
    CREATE TABLE t2(x, y);
  } {wal}
  db close
  
  set fd [open test.db]
  fconfigure $fd -translation binary
  set data [read $fd [expr 20*1024]]
  close $fd
  
  sqlite3 db ""
  db deserialize $data
  
  do_execsql_test 810 {
Changes to test/misc3.test.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
do_test misc3-2.3 {
  execsql {SELECT 000000000002e-0000000025*0.5e25}
} 1.0
do_test misc3-2.4 {
  execsql {SELECT 2e-25*0.5e250}
} 1e+225
do_test misc3-2.5 {
  execsql {SELECT 2.0e-250*0.5e25}
} 1e-225
do_test misc3-2.6 {
  execsql {SELECT '-2.0e-127' * '-0.5e27'}
} 1e-100
do_test misc3-2.7 {
  execsql {SELECT '+2.0e-127' * '-0.5e27'}
} -1e-100
do_test misc3-2.8 {







|
|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
do_test misc3-2.3 {
  execsql {SELECT 000000000002e-0000000025*0.5e25}
} 1.0
do_test misc3-2.4 {
  execsql {SELECT 2e-25*0.5e250}
} 1e+225
do_test misc3-2.5 {
  execsql {SELECT format('%.15e',2.0e-250*0.5e25)}
} {1.0000000000000e-225}
do_test misc3-2.6 {
  execsql {SELECT '-2.0e-127' * '-0.5e27'}
} 1e-100
do_test misc3-2.7 {
  execsql {SELECT '+2.0e-127' * '-0.5e27'}
} -1e-100
do_test misc3-2.8 {
Changes to test/nan.test.
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
      -[string repeat 0 10000].[string repeat 0 324][string repeat 9 10000]
  db eval "INSERT INTO t1 VALUES($small)"
  db eval {SELECT x, typeof(x) FROM t1}
} {0.0 real}

# These tests test some really, really small floating point numbers.
#

if {$tcl_platform(platform) != "symbian"} {
  # These two are not run on symbian because tcl has trouble converting
  # the very small numbers back to text form (probably due to a difference
  # in the sprintf() implementation).
  #
  do_test nan-4.15 {
    db eval {DELETE FROM t1}
    set small \
        [string repeat 0 10000].[string repeat 0 323][string repeat 9 10000]
    db eval "INSERT INTO t1 VALUES($small)"
    db eval {SELECT x, typeof(x) FROM t1}
  } {9.88131291682493e-324 real}
  do_test nan-4.16 {
    db eval {DELETE FROM t1}
    set small \
        -[string repeat 0 10000].[string repeat 0 323][string repeat 9 10000]
    db eval "INSERT INTO t1 VALUES($small)"
    db eval {SELECT x, typeof(x) FROM t1}
  } {-9.88131291682493e-324 real}
}
do_test nan-4.17 {
  db eval {DELETE FROM t1}
  set small [string repeat 0 10000].[string repeat 0 323][string repeat 9 10000]
  db eval "INSERT INTO t1 VALUES($small)"
  db eval {SELECT CAST(x AS text), typeof(x) FROM t1}
} {9.88131291682493e-324 real}







>










|
|





|
|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
      -[string repeat 0 10000].[string repeat 0 324][string repeat 9 10000]
  db eval "INSERT INTO t1 VALUES($small)"
  db eval {SELECT x, typeof(x) FROM t1}
} {0.0 real}

# These tests test some really, really small floating point numbers.
#
load_static_extension db decimal
if {$tcl_platform(platform) != "symbian"} {
  # These two are not run on symbian because tcl has trouble converting
  # the very small numbers back to text form (probably due to a difference
  # in the sprintf() implementation).
  #
  do_test nan-4.15 {
    db eval {DELETE FROM t1}
    set small \
        [string repeat 0 10000].[string repeat 0 323][string repeat 9 10000]
    db eval "INSERT INTO t1 VALUES($small)"
    db eval {SELECT decimal_exp(x), typeof(x) FROM t1}
  } {/9\.88131291682493\d*e-324 real/}
  do_test nan-4.16 {
    db eval {DELETE FROM t1}
    set small \
        -[string repeat 0 10000].[string repeat 0 323][string repeat 9 10000]
    db eval "INSERT INTO t1 VALUES($small)"
    db eval {SELECT decimal_exp(x), typeof(x) FROM t1}
  } {/-9\.88131291682493\d*e-324 real/}
}
do_test nan-4.17 {
  db eval {DELETE FROM t1}
  set small [string repeat 0 10000].[string repeat 0 323][string repeat 9 10000]
  db eval "INSERT INTO t1 VALUES($small)"
  db eval {SELECT CAST(x AS text), typeof(x) FROM t1}
} {9.88131291682493e-324 real}
Changes to test/pendingrace.test.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
}
db_save
db2 close
proc my_db_restore {} {
  forcecopy sv_test.db-journal test.db-journal

  set fd1 [open sv_test.db r]
  fconfigure $fd1 -encoding binary -translation binary
  set data [read $fd1]
  close $fd1

  set fd1 [open test.db w]
  fconfigure $fd1 -encoding binary -translation binary
  puts -nonewline $fd1 $data
  close $fd1
}
my_db_restore
do_test 1.2 {
  file exists test.db-journal
} {1}







|




|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
}
db_save
db2 close
proc my_db_restore {} {
  forcecopy sv_test.db-journal test.db-journal

  set fd1 [open sv_test.db r]
  fconfigure $fd1 -translation binary
  set data [read $fd1]
  close $fd1

  set fd1 [open test.db w]
  fconfigure $fd1 -translation binary
  puts -nonewline $fd1 $data
  close $fd1
}
my_db_restore
do_test 1.2 {
  file exists test.db-journal
} {1}
Changes to test/readonly.test.
11
12
13
14
15
16
17
18



19
20
21
22
23
24
25
#
# This file contains tests for using databases in read-only mode on
# unix.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {$tcl_platform(platform)=="windows"} finish_test



source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
set ::testprefix readonly

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6);







|
>
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#
# This file contains tests for using databases in read-only mode on
# unix.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {$tcl_platform(platform)=="windows"} {
  finish_test
  return
}
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
set ::testprefix readonly

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6);
Changes to test/recover.test.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
    compare_result $db1 $db2 "SELECT * FROM $tbl"
  }
}

proc recover_with_opts {opts} {
  set cmd ".recover $opts"
  set fd [open [list |$::CLI test.db $cmd]]
  fconfigure $fd -encoding binary
  fconfigure $fd -translation binary
  set sql [read $fd]
  close $fd

  forcedelete test.db2
  sqlite3 db2 test.db2
  execsql $sql db2







<







39
40
41
42
43
44
45

46
47
48
49
50
51
52
    compare_result $db1 $db2 "SELECT * FROM $tbl"
  }
}

proc recover_with_opts {opts} {
  set cmd ".recover $opts"
  set fd [open [list |$::CLI test.db $cmd]]

  fconfigure $fd -translation binary
  set sql [read $fd]
  close $fd

  forcedelete test.db2
  sqlite3 db2 test.db2
  execsql $sql db2
Changes to test/rollback.test.
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  foreach i $a { incr cksum $i }
  set mj_pgno [expr $sqlite_pending_byte / 1024]
  set zAppend [binary format Ia*IIa8 $mj_pgno $mj [string length $mj] $cksum \
    "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7"
  ]
  set iOffset [expr (([file size testA.db-journal] + 511)/512)*512]
  set fd [open testA.db-journal a+]
  fconfigure $fd -encoding binary -translation binary
  seek $fd $iOffset
  puts -nonewline $fd $zAppend

  # Also, fix the first journal-header in the journal-file. Because the
  # journal file has not yet been synced, the 8-byte magic string at the
  # start of the first journal-header has not been written by SQLite.
  # So write it now.







|







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  foreach i $a { incr cksum $i }
  set mj_pgno [expr $sqlite_pending_byte / 1024]
  set zAppend [binary format Ia*IIa8 $mj_pgno $mj [string length $mj] $cksum \
    "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7"
  ]
  set iOffset [expr (([file size testA.db-journal] + 511)/512)*512]
  set fd [open testA.db-journal a+]
  fconfigure $fd -translation binary
  seek $fd $iOffset
  puts -nonewline $fd $zAppend

  # Also, fix the first journal-header in the journal-file. Because the
  # journal file has not yet been synced, the 8-byte magic string at the
  # start of the first journal-header has not been written by SQLite.
  # So write it now.
Changes to test/scanstatus2.test.
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
      SELECT 1;
    END;
    INSERT INTO t1 VALUES(1, 2);
  }
  
  proc trace {stmt sql} {
    array set A [sqlite3_stmt_scanstatus -flags complex [format %x $stmt] 0]
    lappend ::trace_explain $A(zExplain)
  }
  db trace_v2 trace 
  
  set ::trace_explain [list]
  do_execsql_test 5.1 {
    DELETE FROM t1 WHERE x=1;







|







261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
      SELECT 1;
    END;
    INSERT INTO t1 VALUES(1, 2);
  }
  
  proc trace {stmt sql} {
    array set A [sqlite3_stmt_scanstatus -flags complex [format %llx $stmt] 0]
    lappend ::trace_explain $A(zExplain)
  }
  db trace_v2 trace 
  
  set ::trace_explain [list]
  do_execsql_test 5.1 {
    DELETE FROM t1 WHERE x=1;
Changes to test/select7.test.
150
151
152
153
154
155
156
































157
158
159
160
161
162
163
      append sql { UNION ALL SELECT 99999999}
      do_test select7-6.2 {
        catchsql $sql
      } {1 {too many terms in compound SELECT}}
    }
  }
}

































# This block of tests verifies that bug aa92c76cd4 is fixed.
#
do_test select7-7.1 {
  execsql {
    CREATE TABLE t3(a REAL);
    INSERT INTO t3 VALUES(44.0);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
      append sql { UNION ALL SELECT 99999999}
      do_test select7-6.2 {
        catchsql $sql
      } {1 {too many terms in compound SELECT}}
    }
  }
}

# https://issues.chromium.org/issues/358174302
# Need to support an unlimited number of terms in a VALUES clause, even
# if some of those terms contain double-quoted string literals.
#
do_execsql_test select7-6.5 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(a,b,c);
}
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 10
sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 0
do_catchsql_test select7-6.6 {
  INSERT INTO t1 VALUES
    (NULL,0,""),  (X'',0.0,0.0),  (X'',X'',""),  (0.0,0.0,""),  (NULL,NULL,0.0),
    (0,"",0),  (0.0,X'',0),  ("",X'',0.0),  (0.0,X'',NULL),  (0,NULL,""),
    (0,"",NULL),  (0.0,NULL,X''),  ("",X'',NULL),  (NULL,0,""),
    (0,NULL,0),  (X'',X'',0.0);
} {1 {no such column: "" - should this be a string literal in single-quotes?}}
do_execsql_test select7-6.7 {
  SELECT count(*) FROM t1;
} {0}
sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_catchsql_test select7-6.8 {
  INSERT INTO t1 VALUES
    (NULL,0,""),  (X'',0.0,0.0),  (X'',X'',""),  (0.0,0.0,""),  (NULL,NULL,0.0),
    (0,"",0),  (0.0,X'',0),  ("",X'',0.0),  (0.0,X'',NULL),  (0,NULL,""),
    (0,"",NULL),  (0.0,NULL,X''),  ("",X'',NULL),  (NULL,0,""),
    (0,NULL,0),  (X'',X'',0.0);
} {0 {}}
do_execsql_test select7-6.9 {
  SELECT count(*) FROM t1;
} {16}

# This block of tests verifies that bug aa92c76cd4 is fixed.
#
do_test select7-7.1 {
  execsql {
    CREATE TABLE t3(a REAL);
    INSERT INTO t3 VALUES(44.0);
Changes to test/shell1.test.
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
    #       return character (and on Windows, the end-of-file character)
    #       cannot be used here.
    #
    if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} {
      continue
    }
    # Tcl 8.7 maps 0x80 through 0x9f into valid UTF8.  So skip those tests.
    if {$i>=0x80 && $i<=0x9f} continue
    if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"}  continue
    if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"}  continue
    set hex [format %02X $i]
    set char [subst \\x$hex]; set oldChar $char
    set escapes [list]
    if {$tcl_platform(platform)=="windows"} {
      #







|







1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
    #       return character (and on Windows, the end-of-file character)
    #       cannot be used here.
    #
    if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} {
      continue
    }
    # Tcl 8.7 maps 0x80 through 0x9f into valid UTF8.  So skip those tests.
    if {$i>=0x80 && ($i<=0x9F || $tcl_version>=9.0)} continue
    if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"}  continue
    if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"}  continue
    set hex [format %02X $i]
    set char [subst \\x$hex]; set oldChar $char
    set escapes [list]
    if {$tcl_platform(platform)=="windows"} {
      #
Changes to test/shell5.test.
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
} {xy\" hello one 2 {} {}}

#----------------------------------------------------------------------------
# Tests for the shell "ascii" import/export mode.
#
do_test shell5-3.1 {
  set fd [open shell5.csv w]
  fconfigure $fd -encoding binary -translation binary
  puts -nonewline $fd "\"test 1\"\x1F,test 2\r\n\x1E"
  puts -nonewline $fd "test 3\x1Ftest 4\n"
  close $fd
  catchcmd test.db {
.mode ascii
CREATE TABLE t5(a, b);
.import shell5.csv t5







|







406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
} {xy\" hello one 2 {} {}}

#----------------------------------------------------------------------------
# Tests for the shell "ascii" import/export mode.
#
do_test shell5-3.1 {
  set fd [open shell5.csv w]
  fconfigure $fd -translation binary
  puts -nonewline $fd "\"test 1\"\x1F,test 2\r\n\x1E"
  puts -nonewline $fd "test 3\x1Ftest 4\n"
  close $fd
  catchcmd test.db {
.mode ascii
CREATE TABLE t5(a, b);
.import shell5.csv t5
Changes to test/shell7.test.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  INSERT INTO f1 VALUES(2, X'01000304');
  INSERT INTO f1 VALUES(3, randomblob(200));
}

foreach {tn l x} [db eval { SELECT tn, length(x) AS l, x FROM f1 }] {
  forcedelete shell7_test.bin
  set fd [open shell7_test.bin w]
  fconfigure $fd -encoding binary
  fconfigure $fd -translation binary
  puts -nonewline $fd $x
  close $fd

  do_test 1.$tn.1 { file size shell7_test.bin } $l
  do_test 1.$tn.2 { 
    catchcmd test.db "INSERT INTO f2 VALUES($tn, readfile('shell7_test.bin'));"







<







29
30
31
32
33
34
35

36
37
38
39
40
41
42
  INSERT INTO f1 VALUES(2, X'01000304');
  INSERT INTO f1 VALUES(3, randomblob(200));
}

foreach {tn l x} [db eval { SELECT tn, length(x) AS l, x FROM f1 }] {
  forcedelete shell7_test.bin
  set fd [open shell7_test.bin w]

  fconfigure $fd -translation binary
  puts -nonewline $fd $x
  close $fd

  do_test 1.$tn.1 { file size shell7_test.bin } $l
  do_test 1.$tn.2 { 
    catchcmd test.db "INSERT INTO f2 VALUES($tn, readfile('shell7_test.bin'));"
Changes to test/superlock.test.
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  do_test 5.$tn.18 { sql1 { SELECT * FROM t1 } } {1 2 3 4 5 6}
  do_test 5.$tn.19 { sql2 { SELECT * FROM t1 } } {1 2 3 4 5 6}
}

proc read_content {file} {
  if {[file exists $file]==0} {return ""}
  set fd [open $file]
  fconfigure $fd -encoding binary -translation binary
  set content [read $fd]
  close $fd
  return $content
}

proc write_content {file content} {
  set fd [open $file w+]
  fconfigure $fd -encoding binary -translation binary
  puts -nonewline $fd $content
  close $fd
}

# Both $file1 and $file2 are database files. This function takes a 
# superlock on each, then exchanges the content of the two files (i.e.
# overwrites $file1 with the initial contents of $file2, and overwrites







|







|







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  do_test 5.$tn.18 { sql1 { SELECT * FROM t1 } } {1 2 3 4 5 6}
  do_test 5.$tn.19 { sql2 { SELECT * FROM t1 } } {1 2 3 4 5 6}
}

proc read_content {file} {
  if {[file exists $file]==0} {return ""}
  set fd [open $file]
  fconfigure $fd -translation binary
  set content [read $fd]
  close $fd
  return $content
}

proc write_content {file content} {
  set fd [open $file w+]
  fconfigure $fd -translation binary
  puts -nonewline $fd $content
  close $fd
}

# Both $file1 and $file2 are database files. This function takes a 
# superlock on each, then exchanges the content of the two files (i.e.
# overwrites $file1 with the initial contents of $file2, and overwrites
Changes to test/syscall.test.
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# file. Whereas a file 2 bytes or larger might be considered corrupt.
#
catch { db close }
forcedelete test.db test.db2

proc create_db_file {nByte} {
  set fd [open test.db w]
  fconfigure $fd -translation binary -encoding binary
  puts -nonewline $fd [string range "xSQLite" 1 $nByte]
  close $fd
}

foreach {nByte res} {
  1      {0 {}}
  2      {1 {file is not a database}}







|







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# file. Whereas a file 2 bytes or larger might be considered corrupt.
#
catch { db close }
forcedelete test.db test.db2

proc create_db_file {nByte} {
  set fd [open test.db w]
  fconfigure $fd -translation binary
  puts -nonewline $fd [string range "xSQLite" 1 $nByte]
  close $fd
}

foreach {nByte res} {
  1      {0 {}}
  2      {1 {file is not a database}}
Changes to test/tester.tcl.
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
      } else {
        file delete $filename
      }
    }
  }
}

if {$::tcl_platform(platform) eq "windows"} {
  proc do_remove_win32_dir {args} {
    set nRetry [getFileRetries]     ;# Maximum number of retries.
    set nDelay [getFileRetryDelay]  ;# Delay in ms before retrying.

    foreach dirName $args {
      # On windows, sometimes even a [remove_win32_dir] can fail just after
      # a directory is emptied. The cause is usually "tag-alongs" - programs
      # like anti-virus software, automatic backup tools and various explorer
      # extensions that keep a file open a little longer than we expect,
      # causing the delete to fail.
      #
      # The solution is to wait a short amount of time before retrying the
      # removal.
      #
      if {$nRetry > 0} {
        for {set i 0} {$i < $nRetry} {incr i} {
          set rc [catch {
            remove_win32_dir $dirName
          } msg]
          if {$rc == 0} break
          if {$nDelay > 0} { after $nDelay }
        }
        if {$rc} { error $msg }
      } else {
        remove_win32_dir $dirName
      }
    }
  }

  proc do_delete_win32_file {args} {
    set nRetry [getFileRetries]     ;# Maximum number of retries.
    set nDelay [getFileRetryDelay]  ;# Delay in ms before retrying.

    foreach fileName $args {
      # On windows, sometimes even a [delete_win32_file] can fail just after
      # a file is closed. The cause is usually "tag-alongs" - programs like
      # anti-virus software, automatic backup tools and various explorer
      # extensions that keep a file open a little longer than we expect,
      # causing the delete to fail.
      #
      # The solution is to wait a short amount of time before retrying the
      # delete.
      #
      if {$nRetry > 0} {
        for {set i 0} {$i < $nRetry} {incr i} {
          set rc [catch {
            delete_win32_file $fileName
          } msg]
          if {$rc == 0} break
          if {$nDelay > 0} { after $nDelay }
        }
        if {$rc} { error $msg }
      } else {
        delete_win32_file $fileName
      }
    }
  }
}

proc execpresql {handle args} {
  trace remove execution $handle enter [list execpresql $handle]
  if {[info exists ::G(perm:presql)]} {
    $handle eval $::G(perm:presql)
  }
}








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







306
307
308
309
310
311
312




























































313
314
315
316
317
318
319
      } else {
        file delete $filename
      }
    }
  }
}





























































proc execpresql {handle args} {
  trace remove execution $handle enter [list execpresql $handle]
  if {[info exists ::G(perm:presql)]} {
    $handle eval $::G(perm:presql)
  }
}

843
844
845
846
847
848
849



850
851
852
853
854
855
856
          set e [string range $expected 1 end]
          set ok [expr {![string match $e $result]}]
        } else {
          set ok [string match $expected $result]
        }
      } else {
        set ok [expr {[string compare $result $expected]==0}]



      }
      if {!$ok} {
        # if {![info exists ::testprefix] || $::testprefix eq ""} {
        #   error "no test prefix"
        # }
        output1 ""
        output2 "! $name expected: \[$expected\]\n! $name got:      \[$result\]"







>
>
>







783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
          set e [string range $expected 1 end]
          set ok [expr {![string match $e $result]}]
        } else {
          set ok [string match $expected $result]
        }
      } else {
        set ok [expr {[string compare $result $expected]==0}]
        if {!$ok} {
          set ok [fpnum_compare $result $expected]
        }
      }
      if {!$ok} {
        # if {![info exists ::testprefix] || $::testprefix eq ""} {
        #   error "no test prefix"
        # }
        output1 ""
        output2 "! $name expected: \[$expected\]\n! $name got:      \[$result\]"
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  set rc [catch { eval $line } msg]
  list $rc $msg
}

proc catchcmdex {db {cmd ""}} {
  global CLI
  set out [open cmds.txt w]
  fconfigure $out -encoding binary -translation binary
  puts -nonewline $out $cmd
  close $out
  set line "exec -keepnewline -- $CLI $db < cmds.txt"
  set chans [list stdin stdout stderr]
  foreach chan $chans {
    catch {
      set modes($chan) [fconfigure $chan]
      fconfigure $chan -encoding binary -translation binary -buffering none
    }
  }
  set rc [catch { eval $line } msg]
  foreach chan $chans {
    catch {
      eval fconfigure [list $chan] $modes($chan)
    }







|







|







836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  set rc [catch { eval $line } msg]
  list $rc $msg
}

proc catchcmdex {db {cmd ""}} {
  global CLI
  set out [open cmds.txt w]
  fconfigure $out -translation binary
  puts -nonewline $out $cmd
  close $out
  set line "exec -keepnewline -- $CLI $db < cmds.txt"
  set chans [list stdin stdout stderr]
  foreach chan $chans {
    catch {
      set modes($chan) [fconfigure $chan]
      fconfigure $chan -translation binary -buffering none
    }
  }
  set rc [catch { eval $line } msg]
  foreach chan $chans {
    catch {
      eval fconfigure [list $chan] $modes($chan)
    }
Changes to test/testrunner.tcl.
50
51
52
53
54
55
56

57
58
59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
proc usage {} {
  set a0 [file tail $::argv0]

  puts stderr [string trim [subst -nocommands {
Usage: 
    $a0 ?SWITCHES? ?PERMUTATION? ?PATTERNS?
    $a0 PERMUTATION FILE

    $a0 help
    $a0 njob ?NJOB?
    $a0 script ?-msvc? CONFIG
    $a0 status

  where SWITCHES are:
    --buildonly              Build test exes but do not run tests
    --config CONFIGS         Only use configs on comma-separate list CONFIGS
    --dryrun                 Write what would have happened to testrunner.log
    --explain                Write summary to stdout
    --jobs NUM               Run tests using NUM separate processes
    --omit CONFIGS           Omit configs on comma-separated list CONFIGS

    --stop-on-coredump       Stop running if any test segfaults
    --stop-on-error          Stop running after any reported error
    --zipvfs ZIPVFSDIR       ZIPVFS source directory

Special values for PERMUTATION that work with plain tclsh:

    list      - show all allowed PERMUTATION arguments.







>



|








>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
proc usage {} {
  set a0 [file tail $::argv0]

  puts stderr [string trim [subst -nocommands {
Usage: 
    $a0 ?SWITCHES? ?PERMUTATION? ?PATTERNS?
    $a0 PERMUTATION FILE
    $a0 errors ?-v|--verbose?
    $a0 help
    $a0 njob ?NJOB?
    $a0 script ?-msvc? CONFIG
    $a0 status ?-d SECS? ?--cls?

  where SWITCHES are:
    --buildonly              Build test exes but do not run tests
    --config CONFIGS         Only use configs on comma-separate list CONFIGS
    --dryrun                 Write what would have happened to testrunner.log
    --explain                Write summary to stdout
    --jobs NUM               Run tests using NUM separate processes
    --omit CONFIGS           Omit configs on comma-separated list CONFIGS
    --status                 Show the full "status" report while running
    --stop-on-coredump       Stop running if any test segfaults
    --stop-on-error          Stop running after any reported error
    --zipvfs ZIPVFSDIR       ZIPVFS source directory

Special values for PERMUTATION that work with plain tclsh:

    list      - show all allowed PERMUTATION arguments.
96
97
98
99
100
101
102

103
104
105
106
107
108





109
110
111
112
113
114
115
If a PERMUTATION is specified and is followed by the path to a Tcl script
instead of a list of patterns, then that single Tcl test script is run
with the specified permutation.

The "status" and "njob" commands are designed to be run from the same
directory as a running testrunner.tcl script that is running tests. The
"status" command prints a report describing the current state and progress 

of the tests. The "njob" command may be used to query or modify the number
of sub-processes the test script uses to run tests.

The "script" command outputs the script used to build a configuration.
Add the "-msvc" option for a Windows-compatible script. For a list of
available configurations enter "$a0 script help".






Full documentation here: https://sqlite.org/src/doc/trunk/doc/testrunner.md
  }]]

  exit 1
}
#-------------------------------------------------------------------------







>
|
|




>
>
>
>
>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
If a PERMUTATION is specified and is followed by the path to a Tcl script
instead of a list of patterns, then that single Tcl test script is run
with the specified permutation.

The "status" and "njob" commands are designed to be run from the same
directory as a running testrunner.tcl script that is running tests. The
"status" command prints a report describing the current state and progress 
of the tests.  Use the "-d N" option to have the status display clear the
screen and repeat every N seconds.  The "njob" command may be used to query
or modify the number of sub-processes the test script uses to run tests.

The "script" command outputs the script used to build a configuration.
Add the "-msvc" option for a Windows-compatible script. For a list of
available configurations enter "$a0 script help".

The "errors" commands shows the output of all tests that failed in the
most recent run.  Complete output is shown if the -v or --verbose options
are used.  Otherwise, an attempt is made to minimize the output to show
only the parts that contain the error messages.

Full documentation here: https://sqlite.org/src/doc/trunk/doc/testrunner.md
  }]]

  exit 1
}
#-------------------------------------------------------------------------
176
177
178
179
180
181
182

183
184
185
186
187
188
189
set TRG(buildonly) 0                ;# True if --buildonly option 
set TRG(config) {}                  ;# Only build the named configurations
set TRG(omitconfig) {}              ;# Do not build these configurations
set TRG(dryrun) 0                   ;# True if --dryrun option 
set TRG(explain) 0                  ;# True for the --explain option
set TRG(stopOnError) 0              ;# Stop running at first failure
set TRG(stopOnCore) 0               ;# Stop on a core-dump


switch -nocase -glob -- $tcl_platform(os) {
  *darwin* {
    set TRG(platform)    osx
    set TRG(make)        make.sh
    set TRG(makecmd)     "bash make.sh"
    set TRG(testfixture) testfixture







>







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
set TRG(buildonly) 0                ;# True if --buildonly option 
set TRG(config) {}                  ;# Only build the named configurations
set TRG(omitconfig) {}              ;# Do not build these configurations
set TRG(dryrun) 0                   ;# True if --dryrun option 
set TRG(explain) 0                  ;# True for the --explain option
set TRG(stopOnError) 0              ;# Stop running at first failure
set TRG(stopOnCore) 0               ;# Stop on a core-dump
set TRG(fullstatus) 0               ;# Full "status" report while running

switch -nocase -glob -- $tcl_platform(os) {
  *darwin* {
    set TRG(platform)    osx
    set TRG(make)        make.sh
    set TRG(makecmd)     "bash make.sh"
    set TRG(testfixture) testfixture
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

397

398
399
400





401
402
403
404
405
406




407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425









426
427
428
429
430
431
432

433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454




455














































456


































































457
458
459
460
461
462
463

  set bMsvc [expr ([llength $argv]==3)]
  set config [lindex $argv [expr [llength $argv]-1]]

  puts [trd_buildscript $config [file dirname $testdir] $bMsvc]
  exit
}
  

#--------------------------------------------------------------------------
# Check if this is the "status" command:
#
if {[llength $argv]==1 
 && [string compare -nocase status [lindex $argv 0]]==0 
} {

  proc display_job {jobdict {tm ""}} {
    array set job $jobdict

    set dfname [format %-60s $job(displayname)]

    set dtm ""

    if {$tm!=""} { set dtm "\[[expr {$tm-$job(starttime)}]ms\]" }

    puts "  $dfname $dtm"
  }






  sqlite3 mydb $TRG(dbname)
  mydb timeout 1000
  mydb eval BEGIN

  set cmdline [mydb one { SELECT value FROM config WHERE name='cmdline' }]
  set nJob [mydb one { SELECT value FROM config WHERE name='njob' }]





  set now [clock_milliseconds]
  set tm [mydb one {
    SELECT 
      COALESCE((SELECT value FROM config WHERE name='end'), $now) -
      (SELECT value FROM config WHERE name='start')
  }]

  set total 0
  foreach s {"" ready running done failed} { set S($s) 0 }
  mydb eval {
    SELECT state, count(*) AS cnt FROM jobs GROUP BY 1
  } {
    incr S($state) $cnt
    incr total $cnt
  }
  set fin [expr $S(done)+$S(failed)]
  if {$cmdline!=""} {set cmdline " $cmdline"}










  set f ""
  if {$S(failed)>0} {
    set f "$S(failed) FAILED, "
  }
  puts "Command line: \[testrunner.tcl$cmdline\]"
  puts "Jobs:         $nJob"
  puts "Summary:      ${tm}ms, ($fin/$total) finished, ${f}$S(running) running"


  set srcdir [file dirname [file dirname $TRG(info_script)]]
  if {$S(running)>0} {
    puts "Running: "
    mydb eval {
      SELECT * FROM jobs WHERE state='running' ORDER BY starttime 
    } job {
      display_job [array get job] $now
    }
  }
  if {$S(failed)>0} {
    puts "Failures: "
    mydb eval {
      SELECT * FROM jobs WHERE state='failed' ORDER BY starttime
    } job {
      display_job [array get job]
    }
    set nOmit [db one {SELECT count(*) FROM jobs WHERE state='omit'}]
    if {$nOmit} {
      puts "$nOmit jobs omitted due to failures"
    }
  }




 














































  mydb close


































































  exit
}

#-------------------------------------------------------------------------
# Parse the command line.
#
for {set ii 0} {$ii < [llength $argv]} {incr ii} {







|
|
<
<

<
<
<
<
|
|
<
|
<
|
>
|
>
|
|

>
>
>
>
>
|
<
|
|
|
|
>
>
>
>
|

|







|








>
>
>
>
>
>
>
>
>




|
|
|
>




|







|




|

|


>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







384
385
386
387
388
389
390
391
392


393




394
395

396

397
398
399
400
401
402
403
404
405
406
407
408
409

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

  set bMsvc [expr ([llength $argv]==3)]
  set config [lindex $argv [expr [llength $argv]-1]]

  puts [trd_buildscript $config [file dirname $testdir] $bMsvc]
  exit
}

# Helper routine for show_status


#




proc display_job {jobdict {tm ""}} {
  array set job $jobdict

  set dfname [format %-60s $job(displayname)]

  set dtm ""
  if {$tm!=""} {
    set dtm [format %-10s "\[[expr {$tm-$job(starttime)}]ms\]"]
  }
  puts "  $dfname $dtm"
}

# This procedure shows the "status" page.  It uses the database
# connect passed in as the "db" parameter.  If the "cls" parameter
# is true, then VT100 escape codes are used to format the display.
#
proc show_status {db cls} {
  global TRG

  $db eval BEGIN
  if {[catch {
    set cmdline [$db one { SELECT value FROM config WHERE name='cmdline' }]
    set nJob [$db one { SELECT value FROM config WHERE name='njob' }]
  } msg]} {
    if {$cls} {puts "\033\[H\033\[2J"}
    puts "Cannot read database: $TRG(dbname)"
    return
  }
  set now [clock_milliseconds]
  set tm [$db one {
    SELECT 
      COALESCE((SELECT value FROM config WHERE name='end'), $now) -
      (SELECT value FROM config WHERE name='start')
  }]

  set total 0
  foreach s {"" ready running done failed} { set S($s) 0 }
  $db eval {
    SELECT state, count(*) AS cnt FROM jobs GROUP BY 1
  } {
    incr S($state) $cnt
    incr total $cnt
  }
  set fin [expr $S(done)+$S(failed)]
  if {$cmdline!=""} {set cmdline " $cmdline"}

  if {$cls} {
    # Move the cursor to the top-left corner.  Each iteration will simply
    # overwrite.
    puts -nonewline "\033\[H"
    flush stdout
    set clreol "\033\[K"
  } else {
    set clreol ""
  }
  set f ""
  if {$S(failed)>0} {
    set f "$S(failed) FAILED, "
  }
  puts "Command line: \[testrunner.tcl$cmdline\]$clreol"
  puts "Jobs:         $nJob  "
  puts "Summary:      ${tm}ms, ($fin/$total) finished,\
                      ${f}$S(running) running  "

  set srcdir [file dirname [file dirname $TRG(info_script)]]
  if {$S(running)>0} {
    puts "Running: "
    $db eval {
      SELECT * FROM jobs WHERE state='running' ORDER BY starttime 
    } job {
      display_job [array get job] $now
    }
  }
  if {$S(failed)>0} {
    puts "Failures: "
    $db eval {
      SELECT * FROM jobs WHERE state='failed' ORDER BY starttime
    } job {
      display_job [array get job]
    }
    set nOmit [$db one {SELECT count(*) FROM jobs WHERE state='omit'}]
    if {$nOmit} {
      puts "$nOmit jobs omitted due to failures$clreol"
    }
  }
  if {$cls} {
    # Clear everything else to the bottom of the screen
    puts -nonewline "\033\[0J"
    flush stdout
  }
  $db eval COMMIT
}

  

#--------------------------------------------------------------------------
# Check if this is the "status" command:
#
if {[llength $argv]>=1 
 && [string compare -nocase status [lindex $argv 0]]==0 
} {
  set delay 0
  set cls 0
  for {set ii 1} {$ii<[llength $argv]} {incr ii} {
    set a0 [lindex $argv $ii]
    if {$a0=="-d" && $ii+1<[llength $argv]} {
      incr ii
      set delay [lindex $argv $ii]
      if {![string is integer -strict $delay]} {
        puts "Argument to -d should be an integer"
        exit 1
      }
    } elseif {$a0=="-cls" || $a0=="--cls"} {
      set cls 1
    } else {
      puts "unknown option: \"$a0\""
      exit 1
    }
  }

  if {![file readable $TRG(dbname)]} {
    puts "Database missing: $TRG(dbname)"
    exit
  }
  sqlite3 mydb $TRG(dbname)
  mydb timeout 2000

  # Clear the whole screen initially.
  #
  if {$delay>0 || $cls} {puts -nonewline "\033\[2J"}

  while {1} {
    show_status mydb [expr {$delay>0 || $cls}]
    if {$delay<=0} break
    after [expr {$delay*1000}]
  }
  mydb close
  exit
}

# Scan the output of all jobs looking for the summary lines that
# report the number of test cases and the number of errors.
# Aggregate these numbers and return them.
#
proc aggregate_test_counts {db} {
  set ncase 0
  set nerr 0
  $db eval {SELECT output FROM jobs WHERE displaytype IN ('tcl','fuzz')} {
    set n 0
    set m 0
    if {[regexp {(\d+) errors out of (\d+) tests} $output all n m]
        && [string is integer -strict $n]
        && [string is integer -strict $m]} {
      incr ncase $m
      incr nerr $n
    } elseif {[regexp {sessionfuzz.*: *(\d+) cases, (\d+) crash} $output \
                      all m n]
              && [string is integer -strict $m]
              && [string is integer -strict $n]} {
      incr ncase $m
      incr nerr $n
    }
  }
  return [list $nerr $ncase]
}

#--------------------------------------------------------------------------
# Check if this is the "errors" command:
#
if {[llength $argv]>=1 && [llength $argv]<=2
 && ([string compare -nocase errors [lindex $argv 0]]==0 ||
     [string match err* [lindex $argv 0]]==1)
} {
  set verbose 0
  for {set ii 1} {$ii<[llength $argv]} {incr ii} {
    set a0 [lindex $argv $ii]
    if {$a0=="-v" || $a0=="--verbose" || $a0=="-verbose"} {
      set verbose 1
    } else {
      puts "unknown option: \"$a0\"".  Use --help for more info."
      exit 1
    }
  }
  set cnt 0
  sqlite3 mydb $TRG(dbname)
  mydb timeout 2000
  mydb eval {SELECT displaytype, displayname, output
               FROM jobs WHERE state='failed'} {
    puts "**** $displayname ****"
    if {$verbose || $displaytype!="tcl"} {
      puts $output
    } else {
      foreach line [split $output \n] {
        if {[string match {!*} $line] || [string match *failed* $line]} {
          puts $line
        }
      }
    }
    incr cnt
  }
  set summary [aggregate_test_counts mydb]
  mydb close
  puts "Total [lindex $summary 0] errors out of [lindex $summary 1] tests"
  exit
}

#-------------------------------------------------------------------------
# Parse the command line.
#
for {set ii 0} {$ii < [llength $argv]} {incr ii} {
486
487
488
489
490
491
492










493
494
495
496
497
498
499
    } elseif {($n>2 && [string match "$a*" --omit]) || $a=="-c"} {
      incr ii
      set TRG(omitconfig) [lindex $argv $ii]
    } elseif {[string match "$a*" --stop-on-error]} {
      set TRG(stopOnError) 1
    } elseif {[string match "$a*" --stop-on-coredump]} {
      set TRG(stopOnCore) 1










    } else {
      usage
    }
  } else {
    lappend TRG(patternlist) [string map {% *} $a]
  }
}







>
>
>
>
>
>
>
>
>
>







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
    } elseif {($n>2 && [string match "$a*" --omit]) || $a=="-c"} {
      incr ii
      set TRG(omitconfig) [lindex $argv $ii]
    } elseif {[string match "$a*" --stop-on-error]} {
      set TRG(stopOnError) 1
    } elseif {[string match "$a*" --stop-on-coredump]} {
      set TRG(stopOnCore) 1
    } elseif {[string match "$a*" --status]} {
      if {$tcl_platform(platform)=="windows"} {
        puts stdout \
"The --status option is not available on Windows. A suggested work-around"
        puts stdout \
"is to run the following command in a separate window:\n"
        puts stdout "   [info nameofexe] $argv0 status -d 2\n"
      } else {
        set TRG(fullstatus) 1
      }
    } else {
      usage
    }
  } else {
    lappend TRG(patternlist) [string map {% *} $a]
  }
}
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
      set ret [array get job]
    }
  }

  return $ret
}

#rename r_get_next_job r_get_next_job_r
#proc r_get_next_job {iJob} {
  #puts [time { set res [r_get_next_job_r $iJob] }]
  #set res
#}

# Usage:
#
#   add_job OPTION ARG OPTION ARG...
#
# where available OPTIONS are:
#
#   -displaytype







<
<
<
<
<
<







746
747
748
749
750
751
752






753
754
755
756
757
758
759
      set ret [array get job]
    }
  }

  return $ret
}







# Usage:
#
#   add_job OPTION ARG OPTION ARG...
#
# where available OPTIONS are:
#
#   -displaytype
959
960
961
962
963
964
965

966
967
968
969
970
971
972
    }
  }
}

proc make_new_testset {} {
  global TRG


  r_write_db {
    trdb eval $TRG(schema)
    set nJob $TRG(nJob)
    set cmdline $TRG(cmdline)
    set tm [clock_milliseconds]
    trdb eval { REPLACE INTO config VALUES('njob', $nJob ); }
    trdb eval { REPLACE INTO config VALUES('cmdline', $cmdline ); }







>







1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
    }
  }
}

proc make_new_testset {} {
  global TRG

  trdb eval {PRAGMA journal_mode=WAL;}
  r_write_db {
    trdb eval $TRG(schema)
    set nJob $TRG(nJob)
    set cmdline $TRG(cmdline)
    set tm [clock_milliseconds]
    trdb eval { REPLACE INTO config VALUES('njob', $nJob ); }
    trdb eval { REPLACE INTO config VALUES('cmdline', $cmdline ); }
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126


1127
1128
1129







1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
    set fd [open $TRG(run) w]
    puts $fd $set_tmp_dir
    puts $fd $job(cmd)
    close $fd
    set fd [open "|$TRG(runcmd) 2>@1" r]
    cd $pwd

    fconfigure $fd -blocking false
    fileevent $fd readable [list script_input_ready $fd $iJob $job(jobid)]
  }

  return 1
}



proc one_line_report {} {
  global TRG








  set tm [expr [clock_milliseconds] - $TRG(starttime)]
  set tm [format "%d" [expr int($tm/1000.0 + 0.5)]]

  r_write_db {
    trdb eval { 
      SELECT displaytype, state, count(*) AS cnt 
      FROM jobs 
      GROUP BY 1, 2 
    } {
      set v($state,$displaytype) $cnt
      incr t($displaytype) $cnt
    }
  }

  set text ""
  foreach j [lsort [array names t]] {
    foreach k {done failed running} { incr v($k,$j) 0 }
    set fin [expr $v(done,$j) + $v(failed,$j)]
    lappend text "${j}($fin/$t($j))"
    if {$v(failed,$j)>0} {
      lappend text "f$v(failed,$j)"
    }
    if {$v(running,$j)>0} {
      lappend text "r$v(running,$j)"
    }
  }

  if {[info exists TRG(reportlength)]} {
    puts -nonewline "[string repeat " " $TRG(reportlength)]\r"
  }
  set report "${tm} [join $text { }]"
  set TRG(reportlength) [string length $report]
  if {[string length $report]<100} {
    puts -nonewline "$report\r"
    flush stdout
  } else {
    puts $report
  }

  after $TRG(reporttime) one_line_report
}

proc launch_some_jobs {} {
  global TRG
  set nJob [trdb one { SELECT value FROM config WHERE name='njob' }]

  while {[dirs_nHelper]<$nJob} {







|






>
>
|


>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
    set fd [open $TRG(run) w]
    puts $fd $set_tmp_dir
    puts $fd $job(cmd)
    close $fd
    set fd [open "|$TRG(runcmd) 2>@1" r]
    cd $pwd

    fconfigure $fd -blocking false -translation binary
    fileevent $fd readable [list script_input_ready $fd $iJob $job(jobid)]
  }

  return 1
}

# Show the testing progress report
#
proc progress_report {} {
  global TRG

  if {$TRG(fullstatus)} {
    if {$::tcl_platform(platform)=="windows"} {
      exec [info nameofexe] $::argv0 status --cls
    } else {
      show_status trdb 1
    }
  } else {
    set tm [expr [clock_milliseconds] - $TRG(starttime)]
    set tm [format "%d" [expr int($tm/1000.0 + 0.5)]]
  
    r_write_db {
      trdb eval { 
        SELECT displaytype, state, count(*) AS cnt 
        FROM jobs 
        GROUP BY 1, 2 
      } {
        set v($state,$displaytype) $cnt
        incr t($displaytype) $cnt
      }
    }
  
    set text ""
    foreach j [lsort [array names t]] {
      foreach k {done failed running} { incr v($k,$j) 0 }
      set fin [expr $v(done,$j) + $v(failed,$j)]
      lappend text "${j}($fin/$t($j))"
      if {$v(failed,$j)>0} {
        lappend text "f$v(failed,$j)"
      }
      if {$v(running,$j)>0} {
        lappend text "r$v(running,$j)"
      }
    }
  
    if {[info exists TRG(reportlength)]} {
      puts -nonewline "[string repeat " " $TRG(reportlength)]\r"
    }
    set report "${tm} [join $text { }]"
    set TRG(reportlength) [string length $report]
    if {[string length $report]<100} {
      puts -nonewline "$report\r"
      flush stdout
    } else {
      puts $report
    }
  }
  after $TRG(reporttime) progress_report
}

proc launch_some_jobs {} {
  global TRG
  set nJob [trdb one { SELECT value FROM config WHERE name='njob' }]

  while {[dirs_nHelper]<$nJob} {
1187
1188
1189
1190
1191
1192
1193

1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
  set ii 0

  set TRG(starttime) [clock_milliseconds]
  set TRG(log) [open $TRG(logname) w]

  launch_some_jobs


  one_line_report
  while {[dirs_nHelper]>0} {
    after 500 {incr ::wakeup}
    vwait ::wakeup
  }
  close $TRG(log)
  one_line_report

  r_write_db {
    set tm [clock_milliseconds]
    trdb eval { REPLACE INTO config VALUES('end', $tm ); }
    set nErr [trdb one {SELECT count(*) FROM jobs WHERE state='failed'}]
    if {$nErr>0} {
      puts "$nErr failures:"







>
|





|







1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
  set ii 0

  set TRG(starttime) [clock_milliseconds]
  set TRG(log) [open $TRG(logname) w]

  launch_some_jobs

  if {$TRG(fullstatus)} {puts "\033\[2J"}
  progress_report
  while {[dirs_nHelper]>0} {
    after 500 {incr ::wakeup}
    vwait ::wakeup
  }
  close $TRG(log)
  progress_report

  r_write_db {
    set tm [clock_milliseconds]
    trdb eval { REPLACE INTO config VALUES('end', $tm ); }
    set nErr [trdb one {SELECT count(*) FROM jobs WHERE state='failed'}]
    if {$nErr>0} {
      puts "$nErr failures:"
Changes to test/testrunner_data.tcl.
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
      exit -1
    fi
    
    SRCDIR="$srcdir"
    TCLDIR="$tcldir"
    
    if [ ! -f Makefile ] ; then
      \$SRCDIR/configure --with-tcl=\$TCL $configOpts 
    fi
    
    $myopts
    CFLAGS="$cflags"
    
    make \$1 "CFLAGS=\$CFLAGS" "OPTS=\$OPTS" $makeOpts
  }]]







|







482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
      exit -1
    fi
    
    SRCDIR="$srcdir"
    TCLDIR="$tcldir"
    
    if [ ! -f Makefile ] ; then
      \$SRCDIR/configure --with-tcl=\$TCLDIR $configOpts 
    fi
    
    $myopts
    CFLAGS="$cflags"
    
    make \$1 "CFLAGS=\$CFLAGS" "OPTS=\$OPTS" $makeOpts
  }]]
Changes to test/tkt-2d1a5c67d.test.
98
99
100
101
102
103
104

105
106
107
108
109
110
111
    INSERT INTO t4 VALUES('xyz');
}

do_test 3.4 {
  set blobs [list]
  for {set i 1} {$i<100} {incr i} {
    set b [db incrblob -readonly t3 b $i]

    read $b
    lappend blobs $b
  }

  execsql COMMIT
  execsql { SELECT * FROM t4 WHERE a = 'xyz' }
} {xyz}







>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    INSERT INTO t4 VALUES('xyz');
}

do_test 3.4 {
  set blobs [list]
  for {set i 1} {$i<100} {incr i} {
    set b [db incrblob -readonly t3 b $i]
    fconfigure $b -translation binary
    read $b
    lappend blobs $b
  }

  execsql COMMIT
  execsql { SELECT * FROM t4 WHERE a = 'xyz' }
} {xyz}
Changes to test/tkt3457.test.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  forcecopy test.db-journal bak.db-journal

  # Fix the first journal-header in the journal-file. Because the
  # journal file has not yet been synced, the 8-byte magic string at the
  # start of the first journal-header has not been written by SQLite.
  # So write it now.
  set fd [open bak.db-journal a+]
  fconfigure $fd -encoding binary -translation binary
  seek $fd 0
  puts -nonewline $fd "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7"
  close $fd

  execsql COMMIT
} {}








|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  forcecopy test.db-journal bak.db-journal

  # Fix the first journal-header in the journal-file. Because the
  # journal file has not yet been synced, the 8-byte magic string at the
  # start of the first journal-header has not been written by SQLite.
  # So write it now.
  set fd [open bak.db-journal a+]
  fconfigure $fd -translation binary
  seek $fd 0
  puts -nonewline $fd "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7"
  close $fd

  execsql COMMIT
} {}

Changes to test/types3.test.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# A variable with only a string representation comes in as TEXT
do_test types3-1.1 {
  set V {}
  append V x
  concat [tcl_variable_type V] [execsql {SELECT typeof(:V)}]
} {string text}

# A variable with an integer representation comes in as INTEGER
do_test types3-1.2 {
  set V [expr {int(1+2)}]
  concat [tcl_variable_type V] [execsql {SELECT typeof(:V)}]
} {int integer}
set V [expr {1+12345678012345}]







|
<

|







14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# A variable with only a string representation comes in as TEXT
do_test types3-1.1 {
  set V [format %s xxxxx]

  concat [tcl_variable_type V] [execsql {SELECT typeof(:V)}]
} {text}

# A variable with an integer representation comes in as INTEGER
do_test types3-1.2 {
  set V [expr {int(1+2)}]
  concat [tcl_variable_type V] [execsql {SELECT typeof(:V)}]
} {int integer}
set V [expr {1+12345678012345}]
Changes to test/vtabH.test.
124
125
126
127
128
129
130
131
132
133
134


135
136
137
138
139
140
141

#-------------------------------------------------------------------------
#
if {$tcl_platform(platform)=="windows"} {
  set drive [string range [pwd] 0 1]
  set ::env(fstreeDrive) $drive
}
if {$tcl_platform(platform)!="windows" || \
    [regexp -nocase -- {^[A-Z]:} $drive]} {
  reset_db
  register_fs_module db


  do_execsql_test 3.0 {
    SELECT name FROM fsdir WHERE dir = '.' AND name = 'test.db';
    SELECT name FROM fsdir WHERE dir = '.' AND name = '.'
  } {test.db .}

  proc sort_files { names {nocase false} } {
    if {$nocase && $::tcl_platform(platform) eq "windows"} {







<
<
|
|
>
>







124
125
126
127
128
129
130


131
132
133
134
135
136
137
138
139
140
141

#-------------------------------------------------------------------------
#
if {$tcl_platform(platform)=="windows"} {
  set drive [string range [pwd] 0 1]
  set ::env(fstreeDrive) $drive
}


reset_db
register_fs_module db
if {$tcl_platform(platform)!="windows" || \
    [regexp -nocase -- {^[A-Z]:} $drive]} {
  do_execsql_test 3.0 {
    SELECT name FROM fsdir WHERE dir = '.' AND name = 'test.db';
    SELECT name FROM fsdir WHERE dir = '.' AND name = '.'
  } {test.db .}

  proc sort_files { names {nocase false} } {
    if {$nocase && $::tcl_platform(platform) eq "windows"} {
Changes to test/wal.test.
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229

      append walhdr [binary format II $c1 $c2]
      logcksum c1 c2 [string range $framehdr 0 7]
      logcksum c1 c2 $framebody
      set framehdr [binary format IIIIII $pg 5 22 23 $c1 $c2]

      set fd [open test.db-wal w]
      fconfigure $fd -encoding binary -translation binary
      puts -nonewline $fd $walhdr
      puts -nonewline $fd $framehdr
      puts -nonewline $fd $framebody
      close $fd
  
      file size test.db-wal
    } [wal_file_size 1 $pgsz]







|







1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229

      append walhdr [binary format II $c1 $c2]
      logcksum c1 c2 [string range $framehdr 0 7]
      logcksum c1 c2 $framebody
      set framehdr [binary format IIIIII $pg 5 22 23 $c1 $c2]

      set fd [open test.db-wal w]
      fconfigure $fd -translation binary
      puts -nonewline $fd $walhdr
      puts -nonewline $fd $framehdr
      puts -nonewline $fd $framebody
      close $fd
  
      file size test.db-wal
    } [wal_file_size 1 $pgsz]
Changes to test/wal2.test.
1094
1095
1096
1097
1098
1099
1100



1101

1102
1103
1104
1105
1106
1107
1108
  
  foreach {tn permissions} {
   1 00644
   2 00666
   3 00600
   4 00755
  } {



    set effective [format %.5o [expr $permissions & ~$umask]]

    do_test wal2-12.2.$tn.1 {
      file attributes test.db -permissions $permissions
      string map {o 0} [file attributes test.db -permissions]
    } $permissions
    do_test wal2-12.2.$tn.2 {
      list [file exists test.db-wal] [file exists test.db-shm]
    } {0 0}







>
>
>
|
>







1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  
  foreach {tn permissions} {
   1 00644
   2 00666
   3 00600
   4 00755
  } {
    if {$tcl_version>=9.0} {
      set effective [format %.5d [expr $permissions & ~$umask]]
    } else {
      set effective [format %.5o [expr $permissions & ~$umask]]
    }
    do_test wal2-12.2.$tn.1 {
      file attributes test.db -permissions $permissions
      string map {o 0} [file attributes test.db -permissions]
    } $permissions
    do_test wal2-12.2.$tn.2 {
      list [file exists test.db-wal] [file exists test.db-shm]
    } {0 0}
Changes to test/wal_common.tcl.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    set c1 0
    set c2 0
    wal_cksum $endian c1 c2 $blob
    append blob [binary format II $c1 $c2]

    set fd [open $filename r+]
    fconfigure $fd -translation binary
    fconfigure $fd -encoding binary
    seek $fd 0
    puts -nonewline $fd $blob
    close $fd
  }

  set fd [open $filename]
  fconfigure $fd -translation binary
  fconfigure $fd -encoding binary
  set blob [read $fd 24]
  close $fd

  binary scan $blob I6 ints
  set ints
}

proc wal_fix_walindex_cksum {hdrvar} {
  upvar $hdrvar hdr
  set c1 0
  set c2 0
  wal_cksum_intlist c1 c2 [lrange $hdr 0 9]
  lset hdr 10 $c1
  lset hdr 11 $c2
}









<







<















<
<
61
62
63
64
65
66
67

68
69
70
71
72
73
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89


    set c1 0
    set c2 0
    wal_cksum $endian c1 c2 $blob
    append blob [binary format II $c1 $c2]

    set fd [open $filename r+]
    fconfigure $fd -translation binary

    seek $fd 0
    puts -nonewline $fd $blob
    close $fd
  }

  set fd [open $filename]
  fconfigure $fd -translation binary

  set blob [read $fd 24]
  close $fd

  binary scan $blob I6 ints
  set ints
}

proc wal_fix_walindex_cksum {hdrvar} {
  upvar $hdrvar hdr
  set c1 0
  set c2 0
  wal_cksum_intlist c1 c2 [lrange $hdr 0 9]
  lset hdr 10 $c1
  lset hdr 11 $c2
}


Changes to test/walcksum.test.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ifcapable !wal {finish_test ; return }

# Read and return the contents of file $filename. Treat the content as
# binary data.
#
proc readfile {filename} {
  set fd [open $filename]
  fconfigure $fd -encoding binary
  fconfigure $fd -translation binary
  set data [read $fd]
  close $fd
  return $data
}

#







<







18
19
20
21
22
23
24

25
26
27
28
29
30
31
ifcapable !wal {finish_test ; return }

# Read and return the contents of file $filename. Treat the content as
# binary data.
#
proc readfile {filename} {
  set fd [open $filename]

  fconfigure $fd -translation binary
  set data [read $fd]
  close $fd
  return $data
}

#
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
proc log_checksum_write {filename iFrame endian} {
  set data [readfile $filename]

  foreach {offset c1 c2} [log_checksum_calc $data $iFrame $endian] {}

  set bin [binary format II $c1 $c2]
  set fd [open $filename r+]
  fconfigure $fd -encoding binary
  fconfigure $fd -translation binary
  seek $fd $offset
  puts -nonewline $fd $bin
  close $fd
}

# Calculate and return the checksum for a particular frame in a WAL.







<







54
55
56
57
58
59
60

61
62
63
64
65
66
67
proc log_checksum_write {filename iFrame endian} {
  set data [readfile $filename]

  foreach {offset c1 c2} [log_checksum_calc $data $iFrame $endian] {}

  set bin [binary format II $c1 $c2]
  set fd [open $filename r+]

  fconfigure $fd -translation binary
  seek $fd $offset
  puts -nonewline $fd $bin
  close $fd
}

# Calculate and return the checksum for a particular frame in a WAL.
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Also update the wal header checksum (since the wal header contents may
# have changed).
#
proc log_checksum_writemagic {filename endian} {
  set val [expr {0x377f0682 | ($endian == "big" ? 1 : 0)}]
  set bin [binary format I $val]
  set fd [open $filename r+]
  fconfigure $fd -encoding binary
  fconfigure $fd -translation binary
  puts -nonewline $fd $bin

  seek $fd 0
  set blob [read $fd 24]
  set c1 0
  set c2 0







<







108
109
110
111
112
113
114

115
116
117
118
119
120
121
# Also update the wal header checksum (since the wal header contents may
# have changed).
#
proc log_checksum_writemagic {filename endian} {
  set val [expr {0x377f0682 | ($endian == "big" ? 1 : 0)}]
  set bin [binary format I $val]
  set fd [open $filename r+]

  fconfigure $fd -translation binary
  puts -nonewline $fd $bin

  seek $fd 0
  set blob [read $fd 24]
  set c1 0
  set c2 0
Changes to test/walslow.test.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
foreach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} {
  do_test 3.3.$incr {
    set FAIL 0
    for {set iOff 0} {$iOff < [wal_file_size 1 1024]} {incr iOff} {

      forcecopy test.db-wal test2.db-wal
      set fd [open test2.db-wal r+]
      fconfigure $fd -encoding binary
      fconfigure $fd -translation binary
  
      seek $fd $iOff
      binary scan [read $fd 1] c x
      seek $fd $iOff
      puts -nonewline $fd [binary format c [expr {($x+$incr)&0xFF}]]
      close $fd







<







105
106
107
108
109
110
111

112
113
114
115
116
117
118
foreach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} {
  do_test 3.3.$incr {
    set FAIL 0
    for {set iOff 0} {$iOff < [wal_file_size 1 1024]} {incr iOff} {

      forcecopy test.db-wal test2.db-wal
      set fd [open test2.db-wal r+]

      fconfigure $fd -translation binary
  
      seek $fd $iOff
      binary scan [read $fd 1] c x
      seek $fd $iOff
      puts -nonewline $fd [binary format c [expr {($x+$incr)&0xFF}]]
      close $fd
Changes to test/win32longpath.test.
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  }
} {1 2 3 4}

set longPath(1) \\\\?\\$path\\[pid]
set uriPath(1a) %5C%5C%3F%5C$path\\[pid]
set uriPath(1b) %5C%5C%3F%5C$rawPath/[pid]

make_win32_dir $longPath(1)

set longPath(2) $longPath(1)\\[string repeat X 255]
set uriPath(2a) $uriPath(1a)\\[string repeat X 255]
set uriPath(2b) $uriPath(1b)/[string repeat X 255]

make_win32_dir $longPath(2)

set longPath(3) $longPath(2)\\[string repeat Y 255]
set uriPath(3a) $uriPath(2a)\\[string repeat Y 255]
set uriPath(3b) $uriPath(2b)/[string repeat Y 255]

make_win32_dir $longPath(3)

set fileName $longPath(3)\\test.db

set uri(1a) file:$uriPath(3a)\\test.db
set uri(1b) file:$uriPath(3b)/test.db
set uri(1c) file:///$uriPath(3a)\\test.db
set uri(1d) file:///$uriPath(3b)/test.db







|





|





|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  }
} {1 2 3 4}

set longPath(1) \\\\?\\$path\\[pid]
set uriPath(1a) %5C%5C%3F%5C$path\\[pid]
set uriPath(1b) %5C%5C%3F%5C$rawPath/[pid]

file mkdir $longPath(1)

set longPath(2) $longPath(1)\\[string repeat X 255]
set uriPath(2a) $uriPath(1a)\\[string repeat X 255]
set uriPath(2b) $uriPath(1b)/[string repeat X 255]

file mkdir $longPath(2)

set longPath(3) $longPath(2)\\[string repeat Y 255]
set uriPath(3a) $uriPath(2a)\\[string repeat Y 255]
set uriPath(3b) $uriPath(2b)/[string repeat Y 255]

file mkdir $longPath(3)

set fileName $longPath(3)\\test.db

set uri(1a) file:$uriPath(3a)\\test.db
set uri(1b) file:$uriPath(3b)/test.db
set uri(1c) file:///$uriPath(3a)\\test.db
set uri(1d) file:///$uriPath(3b)/test.db
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
    INSERT INTO t1 VALUES(8);
    SELECT x FROM t1 ORDER BY x;
    COMMIT;
  }
} {5 6 7 8}

db3 close
# puts "  Database exists \{[exists_win32_path $fileName]\}"

sqlite3 db3 $fileName -vfs win32-longpath

do_test 1.5 {
  db3 eval {
    PRAGMA journal_mode = WAL;
  }







<







88
89
90
91
92
93
94

95
96
97
98
99
100
101
    INSERT INTO t1 VALUES(8);
    SELECT x FROM t1 ORDER BY x;
    COMMIT;
  }
} {5 6 7 8}

db3 close


sqlite3 db3 $fileName -vfs win32-longpath

do_test 1.5 {
  db3 eval {
    PRAGMA journal_mode = WAL;
  }
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    INSERT INTO t1 VALUES(12);
    SELECT x FROM t1 ORDER BY x;
    COMMIT;
  }
} {5 6 7 8 9 10 11 12}

db3 close
# puts "  Database exists \{[exists_win32_path $fileName]\}"

foreach tn {1a 1b 1c 1d 1e 1f} {
  sqlite3 db3 $uri($tn) -vfs win32-longpath -uri 1 -translatefilename 0

  do_test 1.7.$tn {
    db3 eval {
      SELECT x FROM t1 ORDER BY x;
    }
  } {5 6 7 8 9 10 11 12}

  db3 close
}

do_delete_win32_file $fileName
# puts "  Files remaining \{[find_win32_file $longPath(3)\\*]\}"

do_remove_win32_dir $longPath(3)
do_remove_win32_dir $longPath(2)
do_remove_win32_dir $longPath(1)

finish_test







<













<
<
|
|
|
|


110
111
112
113
114
115
116

117
118
119
120
121
122
123
124
125
126
127
128
129


130
131
132
133
134
135
    INSERT INTO t1 VALUES(12);
    SELECT x FROM t1 ORDER BY x;
    COMMIT;
  }
} {5 6 7 8 9 10 11 12}

db3 close


foreach tn {1a 1b 1c 1d 1e 1f} {
  sqlite3 db3 $uri($tn) -vfs win32-longpath -uri 1 -translatefilename 0

  do_test 1.7.$tn {
    db3 eval {
      SELECT x FROM t1 ORDER BY x;
    }
  } {5 6 7 8 9 10 11 12}

  db3 close
}



file delete -force $fileName
file delete -force $longPath(3)
file delete -force $longPath(2)
file delete -force $longPath(1)

finish_test
Changes to test/zipfile.test.
1
2
3
4
5
6
7
8
9
10
11
12

13


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 2017 December 9
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#


package require Tcl 8.6



set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix zipfile

ifcapable !vtab {
  finish_test; return
}
if {[catch {load_static_extension db zipfile} error]} {
  puts "Skipping zipfile tests, hit load error: $error"
  finish_test; return
}
if {[catch {load_static_extension db fileio} error]} {
  puts "Skipping zipfile tests, hit load error: $error"
  finish_test; return
}

proc readfile {f} {
  set fd [open $f]
  fconfigure $fd -translation binary -encoding binary
  set data [read $fd]
  close $fd
  set data
}

unset -nocomplain ::UNZIP













>
|
>
>



















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 2017 December 9
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

if {$tcl_version<8.6} {
  puts "Requires TCL 8.6 or later"
  return
}

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix zipfile

ifcapable !vtab {
  finish_test; return
}
if {[catch {load_static_extension db zipfile} error]} {
  puts "Skipping zipfile tests, hit load error: $error"
  finish_test; return
}
if {[catch {load_static_extension db fileio} error]} {
  puts "Skipping zipfile tests, hit load error: $error"
  finish_test; return
}

proc readfile {f} {
  set fd [open $f]
  fconfigure $fd -translation binary
  set data [read $fd]
  close $fd
  set data
}

unset -nocomplain ::UNZIP

Changes to test/zipfile2.test.
1
2
3
4
5
6
7
8
9
10
11
12

13


14
15
16
17
18
19
20
# 2018 January 30
#
# 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.
#
#***********************************************************************
#


package require Tcl 8.6



set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix zipfile2

ifcapable !vtab {
  finish_test; return












>
|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 2018 January 30
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

if {$tcl_version<8.6} {
  puts "Requires TCL 8.6 or later"
  return
}

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix zipfile2

ifcapable !vtab {
  finish_test; return
Added tool/buildtclext.tcl.




























































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/usr/bin/tclsh
#
set help \
{Run this TCL script to build and install the TCL interface library for
SQLite.  Run the script with the specific "tclsh" for which the installation
should occur.

There must be a valid "tclsqlite3.c" file in the working directory prior
to running this script.  Use "make tclsqlite3.c" to generate that file.

Options:

   --build-only         Only build the extension, don't install it
   --cc COMPILER        Build using this compiler
   --info               Show info on existing SQLite TCL extension installs
   --install-only       Install an extension previously build
   --uninstall          Uninstall the extension

Other options are retained and passed through into the compiler.}


set build 1
set install 1
set uninstall 0
set infoonly 0
set CC {}
set OPTS {}
for {set ii 0} {$ii<[llength $argv]} {incr ii} {
  set a0 [lindex $argv $ii]
  if {$a0=="--install-only"} {
    set build 0
  } elseif {$a0=="--build-only"} {
    set install 0
  } elseif {$a0=="--uninstall"} {
    set build 0
    set install 0
    set uninstall 1
  } elseif {$a0=="--info"} {
    set build 0
    set install 0
    set infoonly 1
  } elseif {$a0=="--cc" && $ii+1<[llength $argv]} {
    incr ii
    set CC [lindex $argv $ii]
  } elseif {[string match -* $a0]} {
    append OPTS " $a0"
  } else {
    puts stderr "Unknown option: \"$a0\"\n"
    puts stderr $help
    exit 1
  }
}

# Find the root of the SQLite source tree
#
set srcdir [file normalize [file dir $argv0]/..]

# Get the SQLite version number into $VERSION
#
set fd [open $srcdir/VERSION]
set VERSION [string trim [read $fd]]
close $fd

if {$tcl_platform(platform)=="windows"} {
  # We are only able to install, uninstall, and list on Windows.
  # The build process is handled by the Makefile.msc, specifically
  # using "nmake /f Makefile.msc pkgIndex.tcl tclsqlite3.dll"
  #
  if {$build} {
    puts "Unable to build on Windows using the builttclext.tcl script."
    puts "To build, run\n"
    puts "   \"nmake /f Makefile.msc pkgIndex.tcl tclsqlite3.dll"
    exit 1
  }
  set OUT tclsqlite3.dll
} else {
  # Figure out the location of the tclConfig.sh file used by the
  # tclsh that is executing this script.
  #
  if {[catch {
    set LIBDIR [tcl::pkgconfig get libdir,install]
  }]} {
    puts stderr "$argv0: tclsh does not support tcl::pkgconfig."
    exit 1
  }
  if {![file exists $LIBDIR]} {
    puts stderr "$argv0: cannot find the tclConfig.sh file."
    puts stderr "$argv0: tclsh reported library directory \"$LIBDIR\"\
                 does not exist."
    exit 1
  }
  if {![file exists $LIBDIR/tclConfig.sh] 
      || [file size $LIBDIR/tclConfig.sh]<5000} {
    set n1 $LIBDIR/tcl$::tcl_version
    if {[file exists $n1/tclConfig.sh]
        && [file size $n1/tclConfig.sh]>5000} {
      set LIBDIR $n1
    } else {
      puts stderr "$argv0: cannot find tclConfig.sh in either $LIBDIR or $n1"
      exit 1
    }
  }

  # Read the tclConfig.sh file into the $tclConfig variable
  #
  #puts "using $LIBDIR/tclConfig.sh"
  set fd [open $LIBDIR/tclConfig.sh rb]
  set tclConfig [read $fd]
  close $fd
  
  # Extract parameter we will need from the tclConfig.sh file
  #
  set TCLMAJOR 8
  regexp {TCL_MAJOR_VERSION='(\d)'} $tclConfig all TCLMAJOR
  set SUFFIX so
  regexp {TCL_SHLIB_SUFFIX='\.([^']+)'} $tclConfig all SUFFIX
  if {$CC==""} {
    set cc {}
    regexp {TCL_CC='([^']+)'} $tclConfig all cc
    if {$cc!=""} {
      set CC $cc
    }
  }
  if {$CC==""} {
    set CC gcc
  }
  set CFLAGS -fPIC
  regexp {TCL_SHLIB_CFLAGS='([^']+)'} $tclConfig all CFLAGS
  set LIBS {}
  regexp {TCL_STUB_LIB_SPEC='([^']+)'} $tclConfig all LIBS
  set INC "-I$srcdir/src"
  set inc {}
  regexp {TCL_INCLUDE_SPEC='([^']+)'} $tclConfig all inc
  if {$inc!=""} {
    append INC " $inc"
  }
  set cmd {${CC} ${CFLAGS} ${LDFLAGS} -shared}
  regexp {TCL_SHLIB_LD='([^']+)'} $tclConfig all cmd
  set LDFLAGS "$INC -DUSE_TCL_STUBS"
  if {[string length $OPTS]>1} {
    append LDFLAGS $OPTS
  }
  set CMD [subst $cmd]
  if {$TCLMAJOR>8} {
    set OUT libtcl9sqlite$VERSION.$SUFFIX
  } else {
    set OUT libsqlite$VERSION.$SUFFIX
  }
}
  
# Show information about prior installs
#
if {$infoonly} {
  set cnt 0
  foreach dir $auto_path {
    foreach subdir [glob -nocomplain -types d $dir/sqlite3*] {
      if {[file exists $subdir/pkgIndex.tcl]} {
        puts $subdir
        incr cnt
      }
    }
  }
  if {$cnt==0} {
    puts "no current installations of the SQLite TCL extension"
  }
  exit
}

# Uninstall the extension
#
if {$uninstall} {
  set cnt 0
  foreach dir $auto_path {
    if {[file isdirectory $dir/sqlite$VERSION]} {
      incr cnt
      if {![file writable $dir] || ![file writable $dir/sqlite$VERSION]} {
        puts "cannot uninstall $dir/sqlite$VERSION - permission denied"
      } else {
        puts "uninstalling $dir/sqlite$VERSION..."
        file delete -force $dir/sqlite$VERSION
      }
    }
  }
  if {$cnt==0} {
    puts "nothing to uninstall"
  }
  exit
}

if {$install} {
  # Figure out where the extension will be installed.  Put the extension
  # in the first writable directory on $auto_path.
  #
  set DEST {}
  foreach dir $auto_path {
    if {[file writable $dir]} {
      set DEST $dir
      break
    } elseif {[glob -nocomplain $dir/sqlite3*/pkgIndex.tcl]!=""} {
      set conflict [lindex [glob $dir/sqlite3*/pkgIndex.tcl] 0]
      puts "Unable to install. There is already a conflicting version"
      puts "of the SQLite TCL Extension that cannot be overwritten at\n"
      puts "   [file dirname $conflict]\n"
      puts "Consider running using sudo to work around this problem."
      exit 1
    }
  }
  if {$DEST==""} {
    puts "None of the directories on \$auto_path are writable by this process,"
    puts "so the installation cannot take place.  Consider running using sudo"
    puts "to work around this problem.\n"
    puts "These are the (unwritable) \$auto_path directories:\n"
    foreach dir $auto_path {
      puts "  *  $dir"
    }
    exit 1
  }
}

if {$build} {
  # Generate the pkgIndex.tcl file
  #
  puts "generating pkgIndex.tcl..."
  set fd [open pkgIndex.tcl w]
  puts $fd [subst -nocommands {# -*- tcl -*-
# Tcl package index file, version ???
#
package ifneeded sqlite3 $VERSION \\
    [list load [file join \$dir $OUT] sqlite3]
}]
  close $fd

  # Generate and execute the command with which to do the compilation.
  #
  set cmd "$CMD tclsqlite3.c -o $OUT $LIBS"
  puts $cmd
  file delete -force $OUT
  catch {exec {*}$cmd} errmsg
  if {$errmsg!="" && ![file exists $OUT]} {
    puts $errmsg
    exit 1
  }
}


if {$install} {
  # Install the extension
  set DEST2 $DEST/sqlite$VERSION
  file mkdir $DEST2
  puts "installing $DEST2/pkgIndex.tcl"
  file copy -force pkgIndex.tcl $DEST2
  puts "installing $DEST2/$OUT"
  file copy -force $OUT $DEST2
}
Added tool/find_tclconfig.tcl.
















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#
# Run this TCL script to find and print the pathname for the tclConfig.sh
# file.  Used by ../configure
#
if {[catch {
  set libdir [tcl::pkgconfig get libdir,install]
}]} {
  puts stderr "tclsh too old:  does not support tcl::pkgconfig"
  exit 1
}
if {![file exists $libdir]} {
  puts stderr "tclsh reported library directory \"$libdir\" does not exist"
  exit 1
}
if {![file exists $libdir/tclConfig.sh]} {
  set n1 $libdir/tcl$::tcl_version
  if {[file exists $n1/tclConfig.sh]} {
    set libdir $n1
  } else {
    puts stderr "cannot find tclConfig.sh in either $libdir or $n1"
    exit 1
  }
}
puts $libdir
Changes to tool/mkmsvcmin.tcl.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  if {[file exists $toFileName]} {
    error "output file \"$toFileName\" already exists"
  }
}

proc readFile { fileName } {
  set file_id [open $fileName RDONLY]
  fconfigure $file_id -encoding binary -translation binary
  set result [read $file_id]
  close $file_id
  return $result
}

proc writeFile { fileName data } {
  set file_id [open $fileName {WRONLY CREAT TRUNC}]
  fconfigure $file_id -encoding binary -translation binary
  puts -nonewline $file_id $data
  close $file_id
  return ""
}

proc escapeSubSpec { data } {
  regsub -all -- {&} $data {\\\&} data







|







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  if {[file exists $toFileName]} {
    error "output file \"$toFileName\" already exists"
  }
}

proc readFile { fileName } {
  set file_id [open $fileName RDONLY]
  fconfigure $file_id -translation binary
  set result [read $file_id]
  close $file_id
  return $result
}

proc writeFile { fileName data } {
  set file_id [open $fileName {WRONLY CREAT TRUNC}]
  fconfigure $file_id -translation binary
  puts -nonewline $file_id $data
  close $file_id
  return ""
}

proc escapeSubSpec { data } {
  regsub -all -- {&} $data {\\\&} data
Changes to tool/mkvsix.tcl.
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

proc readFile { fileName } {
  #
  # NOTE: Reads and returns the entire contents of the specified file, which
  #       may contain binary data.
  #
  set file_id [open $fileName RDONLY]
  fconfigure $file_id -encoding binary -translation binary
  set result [read $file_id]
  close $file_id
  return $result
}

proc writeFile { fileName data } {
  #
  # NOTE: Writes the entire contents of the specified file, which may contain
  #       binary data.
  #
  set file_id [open $fileName {WRONLY CREAT TRUNC}]
  fconfigure $file_id -encoding binary -translation binary
  puts -nonewline $file_id $data
  close $file_id
  return ""
}

#
# TODO: Modify this procedure when a new version of Visual Studio is released.







|











|







152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

proc readFile { fileName } {
  #
  # NOTE: Reads and returns the entire contents of the specified file, which
  #       may contain binary data.
  #
  set file_id [open $fileName RDONLY]
  fconfigure $file_id -translation binary
  set result [read $file_id]
  close $file_id
  return $result
}

proc writeFile { fileName data } {
  #
  # NOTE: Writes the entire contents of the specified file, which may contain
  #       binary data.
  #
  set file_id [open $fileName {WRONLY CREAT TRUNC}]
  fconfigure $file_id -translation binary
  puts -nonewline $file_id $data
  close $file_id
  return ""
}

#
# TODO: Modify this procedure when a new version of Visual Studio is released.
Changes to tool/replace.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/tcl
#
# Replace string with another string -OR- include
# only lines successfully modified with a regular
# expression.
#
fconfigure stdout -translation binary -encoding binary
fconfigure stderr -translation binary -encoding binary
set mode [string tolower [lindex $argv 0]]
set from [lindex $argv 1]
set to [lindex $argv 2]
if {-1 == [lsearch -exact [list exact regsub include] $mode]} {exit 1}
if {[string length $from]==0} {exit 2}
while {![eof stdin]} {
  set line [gets stdin]






|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/tcl
#
# Replace string with another string -OR- include
# only lines successfully modified with a regular
# expression.
#
fconfigure stdout -translation binary
fconfigure stderr -translation binary
set mode [string tolower [lindex $argv 0]]
set from [lindex $argv 1]
set to [lindex $argv 2]
if {-1 == [lsearch -exact [list exact regsub include] $mode]} {exit 1}
if {[string length $from]==0} {exit 2}
while {![eof stdin]} {
  set line [gets stdin]
Changes to tool/restore_jrnl.tcl.
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
      $jrnl_pgno $db_pgno]
  puts [ format {nonce: %08x chksum: %08x} \
      $nonce $chksum]

  # now hex dump the data
  # This is derived from the Tcler's WIKI
  set fid [open $jrnl_name r]
  fconfigure $fid -translation binary -encoding binary
  seek $fid [expr $jrnl_pg_offset+4]
  set data [read $fid $db_pgsz]
  close $fid
  for {set addr 0} {$addr<$db_pgsz} {set addr [expr $addr+16]} {
    # get 16 bytes of data
    set s [string range $data $addr [expr $addr+16]]
    







|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
      $jrnl_pgno $db_pgno]
  puts [ format {nonce: %08x chksum: %08x} \
      $nonce $chksum]

  # now hex dump the data
  # This is derived from the Tcler's WIKI
  set fid [open $jrnl_name r]
  fconfigure $fid -translation binary
  seek $fid [expr $jrnl_pg_offset+4]
  set data [read $fid $db_pgsz]
  close $fid
  for {set addr 0} {$addr<$db_pgsz} {set addr [expr $addr+16]} {
    # get 16 bytes of data
    set s [string range $data $addr [expr $addr+16]]
    
226
227
228
229
230
231
232
233

# check the integrity of the database with the patched journal
sqlite3 db $db_name
do_test restore_jrnl-1.0 {
  catchsql {PRAGMA integrity_check}
} {0 ok}
db close








<
226
227
228
229
230
231
232


# check the integrity of the database with the patched journal
sqlite3 db $db_name
do_test restore_jrnl-1.0 {
  catchsql {PRAGMA integrity_check}
} {0 ok}
db close

Changes to vsixtest/vsixtest.tcl.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

proc readFile { fileName } {
  #
  # NOTE: Reads and returns the entire contents of the specified file, which
  #       may contain binary data.
  #
  set file_id [open $fileName RDONLY]
  fconfigure $file_id -encoding binary -translation binary
  set result [read $file_id]
  close $file_id
  return $result
}

proc writeFile { fileName data } {
  #
  # NOTE: Writes the entire contents of the specified file, which may contain
  #       binary data.
  #
  set file_id [open $fileName {WRONLY CREAT TRUNC}]
  fconfigure $file_id -encoding binary -translation binary
  puts -nonewline $file_id $data
  close $file_id
  return ""
}

proc putsAndEval { command } {
  #







|











|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

proc readFile { fileName } {
  #
  # NOTE: Reads and returns the entire contents of the specified file, which
  #       may contain binary data.
  #
  set file_id [open $fileName RDONLY]
  fconfigure $file_id -translation binary
  set result [read $file_id]
  close $file_id
  return $result
}

proc writeFile { fileName data } {
  #
  # NOTE: Writes the entire contents of the specified file, which may contain
  #       binary data.
  #
  set file_id [open $fileName {WRONLY CREAT TRUNC}]
  fconfigure $file_id -translation binary
  puts -nonewline $file_id $data
  close $file_id
  return ""
}

proc putsAndEval { command } {
  #