SQLite

Check-in [6ef3de810d]
Login

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

Overview
Comment:Merge changes from trunk.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | memdb
Files: files | file ages | folders
SHA3-256: 6ef3de810d54563c227045b16197b8011ce285ea867261946f93b2de55344f29
User & Date: drh 2018-01-24 15:02:53.185
Context
2018-03-01
13:44
Merge the latest enhancements from trunk. (check-in: c8083de14b user: drh tags: memdb)
2018-01-24
15:02
Merge changes from trunk. (check-in: 6ef3de810d user: drh tags: memdb)
14:40
Interchange the numeric codes for CURSOR_VALID and CURSOR_INVALID to obtain a small size decrease and performance increase. (check-in: e0f192ea6d user: drh tags: trunk)
2018-01-03
23:54
Fix compiler warnings on Windows. (check-in: 512b8e40c4 user: drh tags: memdb)
Changes
Unified Diff Ignore Whitespace Patch
Added .fossil-settings/empty-dirs.


>
1
compat
Added .fossil-settings/ignore-glob.


>
1
compat/*
Changes to Makefile.in.
444
445
446
447
448
449
450
451

452
453
454
455
456
457
458
  $(TOP)/ext/misc/percentile.c \
  $(TOP)/ext/misc/regexp.c \
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c


# Source code to the library files needed by the test fixture
#
TESTSRC2 = \
  $(TOP)/src/attach.c \
  $(TOP)/src/backup.c \
  $(TOP)/src/bitvec.c \







|
>







444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  $(TOP)/ext/misc/percentile.c \
  $(TOP)/ext/misc/regexp.c \
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c \
  $(TOP)/ext/misc/zipfile.c

# Source code to the library files needed by the test fixture
#
TESTSRC2 = \
  $(TOP)/src/attach.c \
  $(TOP)/src/backup.c \
  $(TOP)/src/bitvec.c \
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
# executables needed for testing
#
TESTPROGS = \
  testfixture$(TEXE) \
  sqlite3$(TEXE) \
  sqlite3_analyzer$(TEXE) \
  sqldiff$(TEXE) \
  dbhash$(TEXE)


# Databases containing fuzzer test cases
#
FUZZDATA = \
  $(TOP)/test/fuzzdata1.db \
  $(TOP)/test/fuzzdata2.db \
  $(TOP)/test/fuzzdata3.db \
  $(TOP)/test/fuzzdata4.db \
  $(TOP)/test/fuzzdata5.db

# Standard options to testfixture
#
TESTOPTS = --verbose=file --output=test-out.txt

# Extra compiler options for various shell tools
#
SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4
# SHELL_OPT += -DSQLITE_ENABLE_FTS5

SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS







|
>

















|
>







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
# executables needed for testing
#
TESTPROGS = \
  testfixture$(TEXE) \
  sqlite3$(TEXE) \
  sqlite3_analyzer$(TEXE) \
  sqldiff$(TEXE) \
  dbhash$(TEXE) \
  sqltclsh$(TEXE)

# Databases containing fuzzer test cases
#
FUZZDATA = \
  $(TOP)/test/fuzzdata1.db \
  $(TOP)/test/fuzzdata2.db \
  $(TOP)/test/fuzzdata3.db \
  $(TOP)/test/fuzzdata4.db \
  $(TOP)/test/fuzzdata5.db

# Standard options to testfixture
#
TESTOPTS = --verbose=file --output=test-out.txt

# Extra compiler options for various shell tools
#
SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4
#SHELL_OPT += -DSQLITE_ENABLE_FTS5
SHELL_OPT += -DSQLITE_ENABLE_RTREE
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS
992
993
994
995
996
997
998

999
1000
1001





1002
1003
1004
1005
1006
1007
1008
keywordhash.h:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash$(BEXE) >keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \

	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c






shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
	$(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c











>


|
>
>
>
>
>







995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
keywordhash.h:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash$(BEXE) >keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c \
	$(TOP)/ext/misc/sqlar.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
        $(TOP)/src/test_windirent.c

shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
	$(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c




1193
1194
1195
1196
1197
1198
1199






1200
1201
1202
1203
1204
1205
1206
	./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)

sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
	$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c

sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
	$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)







sqlite3_expert$(TEXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
	$(LTLINK)	$(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert $(TLIBS)

CHECKER_DEPS =\
  $(TOP)/tool/mkccode.tcl \
  sqlite3.c \







>
>
>
>
>
>







1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
	./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)

sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
	$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c

sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
	$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)

sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in	
	$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c

sqltclsh$(TEXE): sqltclsh.c
	$(LTLINK) sqltclsh.c -o $@ $(LIBTCL) $(TLIBS)

sqlite3_expert$(TEXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
	$(LTLINK)	$(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert $(TLIBS)

CHECKER_DEPS =\
  $(TOP)/tool/mkccode.tcl \
  sqlite3.c \
Changes to Makefile.msc.
88
89
90
91
92
93
94























95
96
97
98
99
100
101
# be used for debugging with Visual Studio.
#
!IFNDEF SPLIT_AMALGAMATION
SPLIT_AMALGAMATION = 0
!ENDIF

# <<mark>>























# Set this non-0 to use the International Components for Unicode (ICU).
#
!IFNDEF USE_ICU
USE_ICU = 0
!ENDIF
# <</mark>>








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







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
# be used for debugging with Visual Studio.
#
!IFNDEF SPLIT_AMALGAMATION
SPLIT_AMALGAMATION = 0
!ENDIF

# <<mark>>
# Set this non-0 to have this makefile assume the Tcl shell executable
# (tclsh*.exe) is available in the PATH.  By default, this is disabled
# for compatibility with older build environments.  This setting only
# applies if TCLSH_CMD is not set manually.
#
!IFNDEF USE_TCLSH_IN_PATH
USE_TCLSH_IN_PATH = 0
!ENDIF

# Set this non-0 to use zlib, possibly compiling it from source code.
#
!IFNDEF USE_ZLIB
USE_ZLIB = 0
!ENDIF

# Set this non-0 to build zlib from source code.  This is enabled by
# default and in that case it will be assumed that the ZLIBDIR macro
# points to the top-level source code directory for zlib.
#
!IFNDEF BUILD_ZLIB
BUILD_ZLIB = 1
!ENDIF

# Set this non-0 to use the International Components for Unicode (ICU).
#
!IFNDEF USE_ICU
USE_ICU = 0
!ENDIF
# <</mark>>

608
609
610
611
612
613
614









615
616
617
618
619
620
621
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_DEP = $(SQLITE3DLL)
!ELSE
SHELL_CORE_DEP =
!ENDIF
!ENDIF










# This is the core library that the shell executable should link with.
#
!IFNDEF SHELL_CORE_LIB
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_LIB = $(SQLITE3LIB)
!ELSE
SHELL_CORE_LIB =







>
>
>
>
>
>
>
>
>







631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_DEP = $(SQLITE3DLL)
!ELSE
SHELL_CORE_DEP =
!ENDIF
!ENDIF

# <<mark>>
# If zlib support is enabled, add the dependencies for it.
#
!IF $(USE_ZLIB)!=0 && $(BUILD_ZLIB)!=0
SHELL_CORE_DEP = zlib $(SHELL_CORE_DEP)
TESTFIXTURE_DEP = zlib $(TESTFIXTURE_DEP)
!ENDIF
# <</mark>>

# This is the core library that the shell executable should link with.
#
!IFNDEF SHELL_CORE_LIB
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_LIB = $(SQLITE3LIB)
!ELSE
SHELL_CORE_LIB =
798
799
800
801
802
803
804




805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822

























823
824
825
826
827
828
829




830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847

848



849
850
851
852
853
854
855
# <<mark>>
# The locations of the Tcl header and library files.  Also, the library that
# non-stubs enabled programs using Tcl must link against.  These variables
# (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment
# prior to running nmake in order to match the actual installed location and
# version on this machine.
#




!IFNDEF TCLINCDIR
TCLINCDIR = c:\tcl\include
!ENDIF

!IFNDEF TCLLIBDIR
TCLLIBDIR = c:\tcl\lib
!ENDIF

!IFNDEF LIBTCL
LIBTCL = tcl86.lib
!ENDIF

!IFNDEF LIBTCLSTUB
LIBTCLSTUB = tclstub86.lib
!ENDIF

!IFNDEF LIBTCLPATH
LIBTCLPATH = c:\tcl\bin

























!ENDIF

# The locations of the ICU header and library files.  These variables
# (ICUINCDIR, ICULIBDIR, and LIBICU) may be overridden via the environment
# prior to running nmake in order to match the actual installed location on
# this machine.
#




!IFNDEF ICUINCDIR
ICUINCDIR = c:\icu\include
!ENDIF

!IFNDEF ICULIBDIR
ICULIBDIR = c:\icu\lib
!ENDIF

!IFNDEF LIBICU
LIBICU = icuuc.lib icuin.lib
!ENDIF

# This is the command to use for tclsh - normally just "tclsh", but we may
# know the specific version we want to use.  This variable (TCLSH_CMD) may be
# overridden via the environment prior to running nmake in order to select a
# specific Tcl shell to use.
#
!IFNDEF TCLSH_CMD

TCLSH_CMD = tclsh



!ENDIF
# <</mark>>

# Compiler options needed for programs that use the readline() library.
#
!IFNDEF READLINE_FLAGS
READLINE_FLAGS = -DHAVE_READLINE=0







>
>
>
>

|



|











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







>
>
>
>

|



|












>

>
>
>







830
831
832
833
834
835
836
837
838
839
840
841
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
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
# <<mark>>
# The locations of the Tcl header and library files.  Also, the library that
# non-stubs enabled programs using Tcl must link against.  These variables
# (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment
# prior to running nmake in order to match the actual installed location and
# version on this machine.
#
!IFNDEF TCLDIR
TCLDIR = $(TOP)\compat\tcl
!ENDIF

!IFNDEF TCLINCDIR
TCLINCDIR = $(TCLDIR)\include
!ENDIF

!IFNDEF TCLLIBDIR
TCLLIBDIR = $(TCLDIR)\lib
!ENDIF

!IFNDEF LIBTCL
LIBTCL = tcl86.lib
!ENDIF

!IFNDEF LIBTCLSTUB
LIBTCLSTUB = tclstub86.lib
!ENDIF

!IFNDEF LIBTCLPATH
LIBTCLPATH = $(TCLDIR)\bin
!ENDIF

# The locations of the zlib header and library files.  These variables
# (ZLIBINCDIR, ZLIBLIBDIR, and ZLIBLIB) may be overridden via the environment
# prior to running nmake in order to match the actual installed (or source
# code) location on this machine.
#
!IFNDEF ZLIBDIR
ZLIBDIR = $(TOP)\compat\zlib
!ENDIF

!IFNDEF ZLIBINCDIR
ZLIBINCDIR = $(ZLIBDIR)
!ENDIF

!IFNDEF ZLIBLIBDIR
ZLIBLIBDIR = $(ZLIBDIR)
!ENDIF

!IFNDEF ZLIBLIB
!IF $(DYNAMIC_SHELL)!=0
ZLIBLIB = zdll.lib
!ELSE
ZLIBLIB = zlib.lib
!ENDIF
!ENDIF

# The locations of the ICU header and library files.  These variables
# (ICUINCDIR, ICULIBDIR, and LIBICU) may be overridden via the environment
# prior to running nmake in order to match the actual installed location on
# this machine.
#
!IFNDEF ICUDIR
ICUDIR = $(TOP)\compat\icu
!ENDIF

!IFNDEF ICUINCDIR
ICUINCDIR = $(ICUDIR)\include
!ENDIF

!IFNDEF ICULIBDIR
ICULIBDIR = $(ICUDIR)\lib
!ENDIF

!IFNDEF LIBICU
LIBICU = icuuc.lib icuin.lib
!ENDIF

# This is the command to use for tclsh - normally just "tclsh", but we may
# know the specific version we want to use.  This variable (TCLSH_CMD) may be
# overridden via the environment prior to running nmake in order to select a
# specific Tcl shell to use.
#
!IFNDEF TCLSH_CMD
!IF $(USE_TCLSH_IN_PATH)!=0 || !EXIST("$(TCLDIR)\bin\tclsh.exe")
TCLSH_CMD = tclsh
!ELSE
TCLSH_CMD = $(TCLDIR)\bin\tclsh.exe
!ENDIF
!ENDIF
# <</mark>>

# Compiler options needed for programs that use the readline() library.
#
!IFNDEF READLINE_FLAGS
READLINE_FLAGS = -DHAVE_READLINE=0
947
948
949
950
951
952
953









954
955
956
957
958
959
960
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
TCC = $(TCC) -Zi
BCC = $(BCC) -Zi
!ENDIF

# <<mark>>









# If ICU support is enabled, add the compiler options for it.
#
!IF $(USE_ICU)!=0
TCC = $(TCC) -DSQLITE_ENABLE_ICU=1
RCC = $(RCC) -DSQLITE_ENABLE_ICU=1
TCC = $(TCC) -I$(TOP)\ext\icu
RCC = $(RCC) -I$(TOP)\ext\icu







>
>
>
>
>
>
>
>
>







1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
TCC = $(TCC) -Zi
BCC = $(BCC) -Zi
!ENDIF

# <<mark>>
# If zlib support is enabled, add the compiler options for it.
#
!IF $(USE_ZLIB)!=0
TCC = $(TCC) -DSQLITE_HAVE_ZLIB=1
RCC = $(RCC) -DSQLITE_HAVE_ZLIB=1
TCC = $(TCC) -I$(ZLIBINCDIR)
RCC = $(RCC) -I$(ZLIBINCDIR)
!ENDIF

# If ICU support is enabled, add the compiler options for it.
#
!IF $(USE_ICU)!=0
TCC = $(TCC) -DSQLITE_ENABLE_ICU=1
RCC = $(RCC) -DSQLITE_ENABLE_ICU=1
TCC = $(TCC) -I$(TOP)\ext\icu
RCC = $(RCC) -I$(TOP)\ext\icu
1067
1068
1069
1070
1071
1072
1073
1074







1075
1076
1077
1078
1079
1080
1081
1082
LDFLAGS = $(LDOPTS)
!ENDIF

# <<mark>>
# Start with the Tcl related linker options.
#
!IF $(NO_TCL)==0
LTLIBPATHS = /LIBPATH:$(TCLLIBDIR)







LTLIBS = $(LTLIBS) $(LIBTCL)
!ENDIF

# If ICU support is enabled, add the linker options for it.
#
!IF $(USE_ICU)!=0
LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ICULIBDIR)
LTLIBS = $(LTLIBS) $(LIBICU)







|
>
>
>
>
>
>
>
|







1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
LDFLAGS = $(LDOPTS)
!ENDIF

# <<mark>>
# Start with the Tcl related linker options.
#
!IF $(NO_TCL)==0
TCLLIBPATHS = $(TCLLIBPATHS) /LIBPATH:$(TCLLIBDIR)
TCLLIBS = $(TCLLIBS) $(LIBTCL)
!ENDIF

# If zlib support is enabled, add the linker options for it.
#
!IF $(USE_ZLIB)!=0
LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ZLIBLIBDIR)
LTLIBS = $(LTLIBS) $(ZLIBLIB)
!ENDIF

# If ICU support is enabled, add the linker options for it.
#
!IF $(USE_ICU)!=0
LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ICULIBDIR)
LTLIBS = $(LTLIBS) $(LIBICU)
1420
1421
1422
1423
1424
1425
1426






1427
1428
1429
1430
1431
1432
1433
  $(TOP)\ext\misc\regexp.c \
  $(TOP)\ext\misc\remember.c \
  $(TOP)\ext\misc\series.c \
  $(TOP)\ext\misc\spellfix.c \
  $(TOP)\ext\misc\totype.c \
  $(TOP)\ext\misc\unionvtab.c \
  $(TOP)\ext\misc\wholenumber.c







# Source code to the library files needed by the test fixture
# (non-amalgamation)
#
TESTSRC2 = \
  $(SRC00) \
  $(SRC01) \







>
>
>
>
>
>







1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
  $(TOP)\ext\misc\regexp.c \
  $(TOP)\ext\misc\remember.c \
  $(TOP)\ext\misc\series.c \
  $(TOP)\ext\misc\spellfix.c \
  $(TOP)\ext\misc\totype.c \
  $(TOP)\ext\misc\unionvtab.c \
  $(TOP)\ext\misc\wholenumber.c

# If use of zlib is enabled, add the "zipfile.c" source file.
#
!IF $(USE_ZLIB)!=0
TESTEXT = $(TESTEXT) $(TOP)\ext\misc\zipfile.c
!ENDIF

# Source code to the library files needed by the test fixture
# (non-amalgamation)
#
TESTSRC2 = \
  $(SRC00) \
  $(SRC01) \
1492
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
1524
#
TESTPROGS = \
  testfixture.exe \
  $(SQLITE3EXE) \
  sqlite3_analyzer.exe \
  sqlite3_checker.exe \
  sqldiff.exe \
  dbhash.exe


# Databases containing fuzzer test cases
#
FUZZDATA = \
  $(TOP)\test\fuzzdata1.db \
  $(TOP)\test\fuzzdata2.db \
  $(TOP)\test\fuzzdata3.db \
  $(TOP)\test\fuzzdata4.db \
  $(TOP)\test\fuzzdata5.db
# <</mark>>

# Additional compiler options for the shell.  These are only effective
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC -DSQLITE_INTROSPECTION_PRAGMAS

!ENDIF

# <<mark>>
# Extra compiler options for various test tools.
#
MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1







|
>


















>







1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
#
TESTPROGS = \
  testfixture.exe \
  $(SQLITE3EXE) \
  sqlite3_analyzer.exe \
  sqlite3_checker.exe \
  sqldiff.exe \
  dbhash.exe \
  sqltclsh.exe

# Databases containing fuzzer test cases
#
FUZZDATA = \
  $(TOP)\test\fuzzdata1.db \
  $(TOP)\test\fuzzdata2.db \
  $(TOP)\test\fuzzdata3.db \
  $(TOP)\test\fuzzdata4.db \
  $(TOP)\test\fuzzdata5.db
# <</mark>>

# Additional compiler options for the shell.  These are only effective
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC -DSQLITE_INTROSPECTION_PRAGMAS
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_RTREE
!ENDIF

# <<mark>>
# Extra compiler options for various test tools.
#
MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
1542
1543
1544
1545
1546
1547
1548
1549








1550
1551
1552
1553
1554
1555
1556
ALL_TCL_TARGETS =
!ENDIF
# <</mark>>

# This is the default Makefile target.  The objects listed here
# are what get build when you type just "make" with no arguments.
#
all:	dll libsqlite3.lib shell $(ALL_TCL_TARGETS)









# Dynamic link library section.
#
dll:	$(SQLITE3DLL)

# Shell executable.
#







|
>
>
>
>
>
>
>
>







1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
ALL_TCL_TARGETS =
!ENDIF
# <</mark>>

# This is the default Makefile target.  The objects listed here
# are what get build when you type just "make" with no arguments.
#
core:	dll libsqlite3.lib shell

# Targets that require the Tcl library.
#
tcl:	$(ALL_TCL_TARGETS)

# This Makefile target builds all of the standard binaries.
#
all:	core tcl

# Dynamic link library section.
#
dll:	$(SQLITE3DLL)

# Shell executable.
#
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
tclsqlite.lo:	$(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
	$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c

tclsqlite-shell.lo:	$(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
	$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c

tclsqlite3.exe:	tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
	$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS)

# Rules to build opcodes.c and opcodes.h
#
opcodes.c:	opcodes.h $(TOP)\tool\mkopcodec.tcl
	$(TCLSH_CMD) $(TOP)\tool\mkopcodec.tcl opcodes.h > opcodes.c

opcodes.h:	parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl







|







2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
tclsqlite.lo:	$(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
	$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c

tclsqlite-shell.lo:	$(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
	$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c

tclsqlite3.exe:	tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
	$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)

# Rules to build opcodes.c and opcodes.h
#
opcodes.c:	opcodes.h $(TOP)\tool\mkopcodec.tcl
	$(TCLSH_CMD) $(TOP)\tool\mkopcodec.tcl opcodes.h > opcodes.c

opcodes.h:	parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl
1983
1984
1985
1986
1987
1988
1989

1990
1991
1992










1993
1994
1995
1996


1997
1998
1999
2000
2001
2002
2003

keywordhash.h:	$(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
	.\mkkeywordhash.exe > keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)\src\shell.c.in \

	$(TOP)\ext\misc\shathree.c \
	$(TOP)\ext\misc\fileio.c \
	$(TOP)\ext\misc\completion.c











shell.c:	$(SHELL_SRC) $(TOP)\tool\mkshellc.tcl
	$(TCLSH_CMD) $(TOP)\tool\mkshellc.tcl > shell.c




# Rules to build the extension objects.
#
icu.lo:	$(TOP)\ext\icu\icu.c $(HDR) $(EXTHDR)
	$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\icu\icu.c

fts2.lo:	$(TOP)\ext\fts2\fts2.c $(HDR) $(EXTHDR)







>


|
>
>
>
>
>
>
>
>
>
>




>
>







2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117

keywordhash.h:	$(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
	.\mkkeywordhash.exe > keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)\src\shell.c.in \
        $(TOP)\ext\misc\appendvfs.c \
	$(TOP)\ext\misc\shathree.c \
	$(TOP)\ext\misc\fileio.c \
	$(TOP)\ext\misc\completion.c \
	$(TOP)\ext\expert\sqlite3expert.c \
	$(TOP)\ext\expert\sqlite3expert.h \
	$(TOP)\src\test_windirent.c

# If use of zlib is enabled, add the "zipfile.c" source file.
#
!IF $(USE_ZLIB)!=0
SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\sqlar.c
SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\zipfile.c
!ENDIF

shell.c:	$(SHELL_SRC) $(TOP)\tool\mkshellc.tcl
	$(TCLSH_CMD) $(TOP)\tool\mkshellc.tcl > shell.c

zlib:
	pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd

# Rules to build the extension objects.
#
icu.lo:	$(TOP)\ext\icu\icu.c $(HDR) $(EXTHDR)
	$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\icu\icu.c

fts2.lo:	$(TOP)\ext\fts2\fts2.c $(HDR) $(EXTHDR)
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
	type "$(TCLINCDIR)\tcl.h" | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact tclDecls.h sqlite_tclDecls.h \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "typedef (.*?)\(Tcl_" "typedef \1 (SQLITE_TCLAPI Tcl_" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "void (*freeProc)" "void (SQLITE_TCLAPI *freeProc)" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "Tcl_HashEntry *(*findProc)" "Tcl_HashEntry *(SQLITE_TCLAPI *findProc)" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "Tcl_HashEntry *(*createProc)" "Tcl_HashEntry *(SQLITE_TCLAPI *createProc)" >> $(SQLITETCLH)
!ENDIF

testfixture.exe:	$(TESTFIXTURE_SRC) $(SQLITE3H) $(LIBRESOBJS) $(HDR) $(SQLITE_TCL_DEP)
	$(LTLINK) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \
		-DBUILD_sqlite -I$(TCLINCDIR) \
		$(TESTFIXTURE_SRC) \
		/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)

extensiontest:	testfixture.exe testloadext.dll
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)

fulltest:	$(TESTPROGS) fuzztest
	@set PATH=$(LIBTCLPATH);$(PATH)







|



|







2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
	type "$(TCLINCDIR)\tcl.h" | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact tclDecls.h sqlite_tclDecls.h \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "typedef (.*?)\(Tcl_" "typedef \1 (SQLITE_TCLAPI Tcl_" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "void (*freeProc)" "void (SQLITE_TCLAPI *freeProc)" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "Tcl_HashEntry *(*findProc)" "Tcl_HashEntry *(SQLITE_TCLAPI *findProc)" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact "Tcl_HashEntry *(*createProc)" "Tcl_HashEntry *(SQLITE_TCLAPI *createProc)" >> $(SQLITETCLH)
!ENDIF

testfixture.exe:	$(TESTFIXTURE_SRC) $(TESTFIXTURE_DEP) $(SQLITE3H) $(LIBRESOBJS) $(HDR) $(SQLITE_TCL_DEP)
	$(LTLINK) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \
		-DBUILD_sqlite -I$(TCLINCDIR) \
		$(TESTFIXTURE_SRC) \
		/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)

extensiontest:	testfixture.exe testloadext.dll
	@set PATH=$(LIBTCLPATH);$(PATH)
	.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)

fulltest:	$(TESTPROGS) fuzztest
	@set PATH=$(LIBTCLPATH);$(PATH)
2221
2222
2223
2224
2225
2226
2227
2228







2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
	.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)

sqlite3_analyzer.c:	$(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
	$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@

sqlite3_analyzer.exe:	sqlite3_analyzer.c $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
		/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)








sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c
	$(LTLINK) $(NO_WARN)	$(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS)

CHECKER_DEPS =\
  $(TOP)/tool/mkccode.tcl \
  sqlite3.c \
  $(TOP)/src/tclsqlite.c \
  $(TOP)/ext/repair/sqlite3_checker.tcl \
  $(TOP)/ext/repair/checkindex.c \
  $(TOP)/ext/repair/checkfreelist.c \
  $(TOP)/ext/misc/btreeinfo.c \
  $(TOP)/ext/repair/sqlite3_checker.c.in

sqlite3_checker.c:	$(CHECKER_DEPS)
	$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\ext\repair\sqlite3_checker.c.in > $@

sqlite3_checker.exe:	sqlite3_checker.c $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_checker.c \
		/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)

dbdump.exe:	$(TOP)\ext\misc\dbdump.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DDBDUMP_STANDALONE $(TOP)\ext\misc\dbdump.c $(SQLITE3C) \
		/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS)

testloadext.lo:	$(TOP)\src\test_loadext.c
	$(LTCOMPILE) $(NO_WARN) -c $(TOP)\src\test_loadext.c







|
>
>
>
>
>
>
>



















|







2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
	.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)

sqlite3_analyzer.c:	$(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
	$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@

sqlite3_analyzer.exe:	sqlite3_analyzer.c $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
		/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)

sqltclsh.c: sqlite3.c $(TOP)\src\tclsqlite.c $(TOP)\tool\sqltclsh.tcl $(TOP)\ext\misc\appendvfs.c $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in
	$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in >sqltclsh.c

sqltclsh.exe: sqltclsh.c  $(SHELL_CORE_DEP) $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqltclsh.c \
		/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)

sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c
	$(LTLINK) $(NO_WARN)	$(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS)

CHECKER_DEPS =\
  $(TOP)/tool/mkccode.tcl \
  sqlite3.c \
  $(TOP)/src/tclsqlite.c \
  $(TOP)/ext/repair/sqlite3_checker.tcl \
  $(TOP)/ext/repair/checkindex.c \
  $(TOP)/ext/repair/checkfreelist.c \
  $(TOP)/ext/misc/btreeinfo.c \
  $(TOP)/ext/repair/sqlite3_checker.c.in

sqlite3_checker.c:	$(CHECKER_DEPS)
	$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\ext\repair\sqlite3_checker.c.in > $@

sqlite3_checker.exe:	sqlite3_checker.c $(LIBRESOBJS)
	$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_checker.c \
		/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)

dbdump.exe:	$(TOP)\ext\misc\dbdump.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DDBDUMP_STANDALONE $(TOP)\ext\misc\dbdump.c $(SQLITE3C) \
		/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS)

testloadext.lo:	$(TOP)\src\test_loadext.c
	$(LTCOMPILE) $(NO_WARN) -c $(TOP)\src\test_loadext.c
2342
2343
2344
2345
2346
2347
2348

2349
2350
2351
	del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
	del /Q sqlite3.c sqlite3-*.c 2>NUL
	del /Q sqlite3rc.h 2>NUL
	del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL
	del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
	del /Q sqlite-*-output.vsix 2>NUL
	del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL

	del /Q fts5.* fts5parse.* 2>NUL
	del /Q lsm.h lsm1.c 2>NUL
# <</mark>>







>



2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
	del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
	del /Q sqlite3.c sqlite3-*.c 2>NUL
	del /Q sqlite3rc.h 2>NUL
	del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL
	del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
	del /Q sqlite-*-output.vsix 2>NUL
	del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL
	del /Q sqltclsh.exe 2>NUL
	del /Q fts5.* fts5parse.* 2>NUL
	del /Q lsm.h lsm1.c 2>NUL
# <</mark>>
Changes to README.md.
1
2
3
4
5
6
7
8
9
10
11
<h1 align="center">SQLite Source Repository</h1>

This repository contains the complete source code for the SQLite database
engine.  Some test scripts are also include.  However, many other test scripts
and most of the documentation are managed separately.

If you are reading this on a Git mirror someplace, you are doing it wrong.
The [official repository](https://www.sqlite.org/src/) is better.  Go there
now.

## Obtaining The Code



|







1
2
3
4
5
6
7
8
9
10
11
<h1 align="center">SQLite Source Repository</h1>

This repository contains the complete source code for the SQLite database
engine.  Some test scripts are also included.  However, many other test scripts
and most of the documentation are managed separately.

If you are reading this on a Git mirror someplace, you are doing it wrong.
The [official repository](https://www.sqlite.org/src/) is better.  Go there
now.

## Obtaining The Code
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
to the "sqlite3.dll" command line above.  When debugging into the SQLite
code, adding the "DEBUG=1" argument to one of the above command lines is
recommended.

SQLite does not require [Tcl](http://www.tcl.tk/) to run, but a Tcl installation
is required by the makefiles (including those for MSVC).  SQLite contains
a lot of generated code and Tcl is used to do much of that code generation.
The makefiles also require AWK.

## Source Code Tour

Most of the core source files are in the **src/** subdirectory.  The
**src/** folder also contains files used to build the "testfixture" test
harness. The names of the source files used by "testfixture" all begin
with "test".
The **src/** also contains the "shell.c" file
which is the main program for the "sqlite3.exe"
[command-line shell](https://sqlite.org/cli.html) and
the "tclsqlite.c" file which implements the
[TCL bindings](https://sqlite.org/tclsqlite.html) for SQLite.
(Historical note:  SQLite began as a Tcl
extension and only later escaped to the wild as an independent library.)

Test scripts and programs are found in the **test/** subdirectory.
Addtional test code is found in other source repositories.
See [How SQLite Is Tested](http://www.sqlite.org/testing.html) for
additional information.







<











|







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
to the "sqlite3.dll" command line above.  When debugging into the SQLite
code, adding the "DEBUG=1" argument to one of the above command lines is
recommended.

SQLite does not require [Tcl](http://www.tcl.tk/) to run, but a Tcl installation
is required by the makefiles (including those for MSVC).  SQLite contains
a lot of generated code and Tcl is used to do much of that code generation.


## Source Code Tour

Most of the core source files are in the **src/** subdirectory.  The
**src/** folder also contains files used to build the "testfixture" test
harness. The names of the source files used by "testfixture" all begin
with "test".
The **src/** also contains the "shell.c" file
which is the main program for the "sqlite3.exe"
[command-line shell](https://sqlite.org/cli.html) and
the "tclsqlite.c" file which implements the
[Tcl bindings](https://sqlite.org/tclsqlite.html) for SQLite.
(Historical note:  SQLite began as a Tcl
extension and only later escaped to the wild as an independent library.)

Test scripts and programs are found in the **test/** subdirectory.
Addtional test code is found in other source repositories.
See [How SQLite Is Tested](http://www.sqlite.org/testing.html) for
additional information.
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
the src/parse.y file.  The conversion of "parse.y" into "parse.c" is done
by the [lemon](./doc/lemon.html) LALR(1) parser generator.  The source code
for lemon is at tool/lemon.c.  Lemon uses the tool/lempar.c file as a
template for generating its parser.

Lemon also generates the **parse.h** header file, at the same time it
generates parse.c. But the parse.h header file is
modified further (to add additional symbols) using the ./addopcodes.awk
AWK script.

The **opcodes.h** header file contains macros that define the numbers
corresponding to opcodes in the "VDBE" virtual machine.  The opcodes.h
file is generated by the scanning the src/vdbe.c source file.  The
AWK script at ./mkopcodeh.awk does this scan and generates opcodes.h.
A second AWK script, ./mkopcodec.awk, then scans opcodes.h to generate
the **opcodes.c** source file, which contains a reverse mapping from
opcode-number to opcode-name that is used for EXPLAIN output.

The **keywordhash.h** header file contains the definition of a hash table
that maps SQL language keywords (ex: "CREATE", "SELECT", "INDEX", etc.) into
the numeric codes used by the parse.c parser.  The keywordhash.h file is
generated by a C-language program at tool mkkeywordhash.c.







|
|




|
|







158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
the src/parse.y file.  The conversion of "parse.y" into "parse.c" is done
by the [lemon](./doc/lemon.html) LALR(1) parser generator.  The source code
for lemon is at tool/lemon.c.  Lemon uses the tool/lempar.c file as a
template for generating its parser.

Lemon also generates the **parse.h** header file, at the same time it
generates parse.c. But the parse.h header file is
modified further (to add additional symbols) using the ./addopcodes.tcl
Tcl script.

The **opcodes.h** header file contains macros that define the numbers
corresponding to opcodes in the "VDBE" virtual machine.  The opcodes.h
file is generated by the scanning the src/vdbe.c source file.  The
Tcl script at ./mkopcodeh.tcl does this scan and generates opcodes.h.
A second Tcl script, ./mkopcodec.tcl, then scans opcodes.h to generate
the **opcodes.c** source file, which contains a reverse mapping from
opcode-number to opcode-name that is used for EXPLAIN output.

The **keywordhash.h** header file contains the definition of a hash table
that maps SQL language keywords (ex: "CREATE", "SELECT", "INDEX", etc.) into
the numeric codes used by the parse.c parser.  The keywordhash.h file is
generated by a C-language program at tool mkkeywordhash.c.
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

  *  **tclsqlite.c** - This file implements the Tcl bindings for SQLite.  It
     is not part of the core SQLite library.  But as most of the tests in this
     repository are written in Tcl, the Tcl language bindings are important.

  *  **test*.c** - Files in the src/ folder that begin with "test" go into
     building the "testfixture.exe" program.  The testfixture.exe program is
     an enhanced TCL shell.  The testfixture.exe program runs scripts in the
     test/ folder to validate the core SQLite code.  The testfixture program
     (and some other test programs too) is build and run when you type
     "make test".

  *  **ext/misc/json1.c** - This file implements the various JSON functions
     that are build into SQLite.








|







275
276
277
278
279
280
281
282
283
284
285
286
287
288
289

  *  **tclsqlite.c** - This file implements the Tcl bindings for SQLite.  It
     is not part of the core SQLite library.  But as most of the tests in this
     repository are written in Tcl, the Tcl language bindings are important.

  *  **test*.c** - Files in the src/ folder that begin with "test" go into
     building the "testfixture.exe" program.  The testfixture.exe program is
     an enhanced Tcl shell.  The testfixture.exe program runs scripts in the
     test/ folder to validate the core SQLite code.  The testfixture program
     (and some other test programs too) is build and run when you type
     "make test".

  *  **ext/misc/json1.c** - This file implements the various JSON functions
     that are build into SQLite.

Changes to VERSION.
1
3.22.0
|
1
3.23.0
Changes to autoconf/Makefile.am.
1
2
3
4
5
6
7
8
9

AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ @SESSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE

lib_LTLIBRARIES = libsqlite3.la
libsqlite3_la_SOURCES = sqlite3.c
libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8

bin_PROGRAMS = sqlite3
sqlite3_SOURCES = shell.c sqlite3.h

|







1
2
3
4
5
6
7
8
9

AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ @ZLIB_FLAGS@ @SESSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE

lib_LTLIBRARIES = libsqlite3.la
libsqlite3_la_SOURCES = sqlite3.c
libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8

bin_PROGRAMS = sqlite3
sqlite3_SOURCES = shell.c sqlite3.h
Changes to autoconf/Makefile.msc.
556
557
558
559
560
561
562

563
564
565
566
567
568
569
!IFNDEF SHELL_CORE_DEP
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_DEP = $(SQLITE3DLL)
!ELSE
SHELL_CORE_DEP =
!ENDIF
!ENDIF


# This is the core library that the shell executable should link with.
#
!IFNDEF SHELL_CORE_LIB
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_LIB = $(SQLITE3LIB)
!ELSE







>







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
!IFNDEF SHELL_CORE_DEP
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_DEP = $(SQLITE3DLL)
!ELSE
SHELL_CORE_DEP =
!ENDIF
!ENDIF


# This is the core library that the shell executable should link with.
#
!IFNDEF SHELL_CORE_LIB
!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0
SHELL_CORE_LIB = $(SQLITE3LIB)
!ELSE
925
926
927
928
929
930
931

932
933
934
935
936
937
938








939
940
941
942
943
944
945

# Additional compiler options for the shell.  These are only effective
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB

!ENDIF


# This is the default Makefile target.  The objects listed here
# are what get build when you type just "make" with no arguments.
#
all:	dll shell









# Dynamic link library section.
#
dll:	$(SQLITE3DLL)

# Shell executable.
#







>






|
>
>
>
>
>
>
>
>







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

# Additional compiler options for the shell.  These are only effective
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC -DSQLITE_INTROSPECTION_PRAGMAS
!ENDIF


# This is the default Makefile target.  The objects listed here
# are what get build when you type just "make" with no arguments.
#
core:	dll shell

# Targets that require the Tcl library.
#
tcl:	$(ALL_TCL_TARGETS)

# This Makefile target builds all of the standard binaries.
#
all:	core tcl

# Dynamic link library section.
#
dll:	$(SQLITE3DLL)

# Shell executable.
#
Changes to autoconf/configure.ac.
160
161
162
163
164
165
166




167
168
169
170
171
172
173
else
  EXTRA_SHELL_OBJ=libsqlite3.la
fi
AC_SUBST(EXTRA_SHELL_OBJ)
#-----------------------------------------------------------------------

AC_CHECK_FUNCS(posix_fallocate)





#-----------------------------------------------------------------------
# UPDATE: Maybe it's better if users just set CFLAGS before invoking
# configure. This option doesn't really add much...
#
#   --enable-tempstore
#







>
>
>
>







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
else
  EXTRA_SHELL_OBJ=libsqlite3.la
fi
AC_SUBST(EXTRA_SHELL_OBJ)
#-----------------------------------------------------------------------

AC_CHECK_FUNCS(posix_fallocate)
AC_CHECK_HEADERS(zlib.h,[
  AC_SEARCH_LIBS(deflate,z,[ZLIB_FLAGS="-DSQLITE_HAVE_ZLIB"])
])
AC_SUBST(ZLIB_FLAGS)

#-----------------------------------------------------------------------
# UPDATE: Maybe it's better if users just set CFLAGS before invoking
# configure. This option doesn't really add much...
#
#   --enable-tempstore
#
Changes to configure.
1
2
3
4
5
6
7
8
9
10
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.22.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.


|







1
2
3
4
5
6
7
8
9
10
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.23.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.22.0'
PACKAGE_STRING='sqlite 3.22.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H







|
|







722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.23.0'
PACKAGE_STRING='sqlite 3.23.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures sqlite 3.22.0 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.







|







1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures sqlite 3.23.0 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of sqlite 3.22.0:";;
   esac
  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]







|







1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of sqlite 3.23.0:";;
   esac
  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
sqlite configure 3.22.0
generated by GNU Autoconf 2.69

Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit







|







1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
sqlite configure 3.23.0
generated by GNU Autoconf 2.69

Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by sqlite $as_me 3.22.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{







|







2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by sqlite $as_me 3.23.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
12238
12239
12240
12241
12242
12243
12244
12245
12246
12247
12248
12249
12250
12251
12252
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.22.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@







|







12238
12239
12240
12241
12242
12243
12244
12245
12246
12247
12248
12249
12250
12251
12252
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.23.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@
12304
12305
12306
12307
12308
12309
12310
12311
12312
12313
12314
12315
12316
12317
12318

Report bugs to the package provider."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.22.0
configured by $0, generated by GNU Autoconf 2.69,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."








|







12304
12305
12306
12307
12308
12309
12310
12311
12312
12313
12314
12315
12316
12317
12318

Report bugs to the package provider."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.23.0
configured by $0, generated by GNU Autoconf 2.69,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."

Changes to ext/expert/expert1.test.
18
19
20
21
22
23
24





25
26
27
28
29
30
31
#
#
if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl
set testprefix expert1






set CLI [test_binary_name sqlite3]
set CMD [test_binary_name sqlite3_expert]

proc squish {txt} {
  regsub -all {[[:space:]]+} $txt { }
}







>
>
>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#
#
if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl
set testprefix expert1

if {[info commands sqlite3_expert_new]==""} {
  finish_test
  return
}

set CLI [test_binary_name sqlite3]
set CMD [test_binary_name sqlite3_expert]

proc squish {txt} {
  regsub -all {[[:space:]]+} $txt { }
}
Changes to ext/expert/sqlite3expert.c.
11
12
13
14
15
16
17


18
19
20
21
22
23
24
*************************************************************************
*/
#include "sqlite3expert.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>



typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;

typedef struct IdxColumn IdxColumn;
typedef struct IdxConstraint IdxConstraint;
typedef struct IdxScan IdxScan;
typedef struct IdxStatement IdxStatement;







>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
*************************************************************************
*/
#include "sqlite3expert.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE 

typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;

typedef struct IdxColumn IdxColumn;
typedef struct IdxConstraint IdxConstraint;
typedef struct IdxScan IdxScan;
typedef struct IdxStatement IdxStatement;
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
          pScan->pOrder = pNew;
          n++;
        }
      }
    }
  }

  pIdxInfo->estimatedCost = 1000000.0 / n;
  return rc;
}

static int expertUpdate(
  sqlite3_vtab *pVtab, 
  int nData, 
  sqlite3_value **azData, 
  sqlite_int64 *pRowid
){




  return SQLITE_OK;
}

/* 
** Virtual table module xOpen method.
*/
static int expertOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  int rc = SQLITE_OK;
  ExpertCsr *pCsr;

  pCsr = idxMalloc(&rc, sizeof(ExpertCsr));
  *ppCursor = (sqlite3_vtab_cursor*)pCsr;
  return rc;
}

/* 
** Virtual table module xClose method.







|









>
>
>
>









>







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
          pScan->pOrder = pNew;
          n++;
        }
      }
    }
  }

  pIdxInfo->estimatedCost = 1000000.0 / (n+1);
  return rc;
}

static int expertUpdate(
  sqlite3_vtab *pVtab, 
  int nData, 
  sqlite3_value **azData, 
  sqlite_int64 *pRowid
){
  (void)pVtab;
  (void)nData;
  (void)azData;
  (void)pRowid;
  return SQLITE_OK;
}

/* 
** Virtual table module xOpen method.
*/
static int expertOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  int rc = SQLITE_OK;
  ExpertCsr *pCsr;
  (void)pVTab;
  pCsr = idxMalloc(&rc, sizeof(ExpertCsr));
  *ppCursor = (sqlite3_vtab_cursor*)pCsr;
  return rc;
}

/* 
** Virtual table module xClose method.
559
560
561
562
563
564
565

566
567
568
569
570
571
572
  return rc;
}

/* 
** Virtual table module xRowid method.
*/
static int expertRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){

  *pRowid = 0;
  return SQLITE_OK;
}

/* 
** Virtual table module xColumn method.
*/







>







566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  return rc;
}

/* 
** Virtual table module xRowid method.
*/
static int expertRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  (void)cur;
  *pRowid = 0;
  return SQLITE_OK;
}

/* 
** Virtual table module xColumn method.
*/
589
590
591
592
593
594
595




596
597
598
599
600
601
602
  int argc, sqlite3_value **argv
){
  ExpertCsr *pCsr = (ExpertCsr*)cur;
  ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab);
  sqlite3expert *pExpert = pVtab->pExpert;
  int rc;





  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
    );
  }







>
>
>
>







597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
  int argc, sqlite3_value **argv
){
  ExpertCsr *pCsr = (ExpertCsr*)cur;
  ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab);
  sqlite3expert *pExpert = pVtab->pExpert;
  int rc;

  (void)idxNum;
  (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
    );
  }
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
  if( *pRc==SQLITE_OK ){
    zAppend = sqlite3_vmprintf(zFmt, ap);
    if( zAppend ){
      nAppend = STRLEN(zAppend);
      zRet = (char*)sqlite3_malloc(nIn + nAppend + 1);
    }
    if( zAppend && zRet ){
      memcpy(zRet, zIn, nIn);
      memcpy(&zRet[nIn], zAppend, nAppend+1);
    }else{
      sqlite3_free(zRet);
      zRet = 0;
      *pRc = SQLITE_NOMEM;
    }
    sqlite3_free(zAppend);







|







762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  if( *pRc==SQLITE_OK ){
    zAppend = sqlite3_vmprintf(zFmt, ap);
    if( zAppend ){
      nAppend = STRLEN(zAppend);
      zRet = (char*)sqlite3_malloc(nIn + nAppend + 1);
    }
    if( zAppend && zRet ){
      if( nIn ) memcpy(zRet, zIn, nIn);
      memcpy(&zRet[nIn], zAppend, nAppend+1);
    }else{
      sqlite3_free(zRet);
      zRet = 0;
      *pRc = SQLITE_NOMEM;
    }
    sqlite3_free(zAppend);
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  sqlite3 *dbm = p->dbm;
  int rc = SQLITE_OK;
  if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
    IdxTable *pTab = pScan->pTab;
    char *zCols = 0;
    char *zIdx = 0;
    IdxConstraint *pCons;
    int h = 0;
    const char *zFmt;

    for(pCons=pEq; pCons; pCons=pCons->pLink){
      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    }
    for(pCons=pTail; pCons; pCons=pCons->pLink){
      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);







|







916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
  sqlite3 *dbm = p->dbm;
  int rc = SQLITE_OK;
  if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
    IdxTable *pTab = pScan->pTab;
    char *zCols = 0;
    char *zIdx = 0;
    IdxConstraint *pCons;
    unsigned int h = 0;
    const char *zFmt;

    for(pCons=pEq; pCons; pCons=pCons->pLink){
      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    }
    for(pCons=pTail; pCons; pCons=pCons->pLink){
      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  return rc;
}

/*
** Create candidate indexes in database [dbm] based on the data in 
** linked-list pScan.
*/
static int idxCreateCandidates(sqlite3expert *p, char **pzErr){
  int rc = SQLITE_OK;
  IdxScan *pIter;

  for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
    rc = idxCreateFromWhere(p, pIter, 0);
    if( rc==SQLITE_OK && pIter->pOrder ){
      rc = idxCreateFromWhere(p, pIter, pIter->pOrder);







|







1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  return rc;
}

/*
** Create candidate indexes in database [dbm] based on the data in 
** linked-list pScan.
*/
static int idxCreateCandidates(sqlite3expert *p){
  int rc = SQLITE_OK;
  IdxScan *pIter;

  for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
    rc = idxCreateFromWhere(p, pIter, 0);
    if( rc==SQLITE_OK && pIter->pOrder ){
      rc = idxCreateFromWhere(p, pIter, pIter->pOrder);
1162
1163
1164
1165
1166
1167
1168


1169
1170
1171
1172
1173
1174
1175
  int eOp,
  const char *z3,
  const char *z4,
  const char *zDb,
  const char *zTrigger
){
  int rc = SQLITE_OK;


  if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){
    if( sqlite3_stricmp(zDb, "main")==0 ){
      sqlite3expert *p = (sqlite3expert*)pCtx;
      IdxTable *pTab;
      for(pTab=p->pTable; pTab; pTab=pTab->pNext){
        if( 0==sqlite3_stricmp(z3, pTab->zName) ) break;
      }







>
>







1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
  int eOp,
  const char *z3,
  const char *z4,
  const char *zDb,
  const char *zTrigger
){
  int rc = SQLITE_OK;
  (void)z4;
  (void)zTrigger;
  if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){
    if( sqlite3_stricmp(zDb, "main")==0 ){
      sqlite3expert *p = (sqlite3expert*)pCtx;
      IdxTable *pTab;
      for(pTab=p->pTable; pTab; pTab=pTab->pNext){
        if( 0==sqlite3_stricmp(z3, pTab->zName) ) break;
      }
1364
1365
1366
1367
1368
1369
1370

1371
1372
1373
1374
1375
1376
1377
  sqlite3_context *pCtx,
  int argc,
  sqlite3_value **argv
){
  struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx);
  int bRet;


  assert( argc==0 );
  if( p->nRow==0.0 ){
    bRet = 1;
  }else{
    bRet = (p->nRet / p->nRow) <= p->target;
    if( bRet==0 ){
      unsigned short rnd;







>







1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
  sqlite3_context *pCtx,
  int argc,
  sqlite3_value **argv
){
  struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx);
  int bRet;

  (void)argv;
  assert( argc==0 );
  if( p->nRow==0.0 ){
    bRet = 1;
  }else{
    bRet = (p->nRet / p->nRow) <= p->target;
    if( bRet==0 ){
      unsigned short rnd;
1519
1520
1521
1522
1523
1524
1525

1526
1527
1528
1529
1530
1531
1532
    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);
  }

  if( rc==SQLITE_OK ){
    if( p->iSample==100 ){
      zQuery = sqlite3_mprintf(
          "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder
      );
    }else{
      zQuery = sqlite3_mprintf(







>







1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
    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(
          "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder
      );
    }else{
      zQuery = sqlite3_mprintf(
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
  IdxHashEntry *pEntry;

  /* Do trigger processing to collect any extra IdxScan structures */
  rc = idxProcessTriggers(p, pzErr);

  /* Create candidate indexes within the in-memory database file */
  if( rc==SQLITE_OK ){
    rc = idxCreateCandidates(p, pzErr);
  }

  /* Generate the stat1 data */
  if( rc==SQLITE_OK ){
    rc = idxPopulateStat1(p, pzErr);
  }








|







1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
  IdxHashEntry *pEntry;

  /* Do trigger processing to collect any extra IdxScan structures */
  rc = idxProcessTriggers(p, pzErr);

  /* Create candidate indexes within the in-memory database file */
  if( rc==SQLITE_OK ){
    rc = idxCreateCandidates(p);
  }

  /* Generate the stat1 data */
  if( rc==SQLITE_OK ){
    rc = idxPopulateStat1(p, pzErr);
  }

1928
1929
1930
1931
1932
1933
1934


    idxTableFree(p->pTable);
    idxWriteFree(p->pWrite);
    idxHashClear(&p->hIdx);
    sqlite3_free(p->zCandidates);
    sqlite3_free(p);
  }
}









>
>
1944
1945
1946
1947
1948
1949
1950
1951
1952
    idxTableFree(p->pTable);
    idxWriteFree(p->pWrite);
    idxHashClear(&p->hIdx);
    sqlite3_free(p->zCandidates);
    sqlite3_free(p);
  }
}

#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
Changes to ext/expert/test_expert.c.
22
23
24
25
26
27
28


29
30
31
32
33
34
35
#else
#  include "tcl.h"
#  ifndef SQLITE_TCLAPI
#    define SQLITE_TCLAPI
#  endif
#endif



/*
** Extract an sqlite3* db handle from the object passed as the second
** argument. If successful, set *pDb to point to the db handle and return
** TCL_OK. Otherwise, return TCL_ERROR.
*/
static int dbHandleFromObj(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **pDb){
  Tcl_CmdInfo info;







>
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#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.
*/
static int dbHandleFromObj(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **pDb){
  Tcl_CmdInfo info;
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
  }

  sqlite3_free(zCmd);
  sqlite3_free(zErr);
  return rc;
}



int TestExpert_Init(Tcl_Interp *interp){

  struct Cmd {
    const char *zCmd;
    Tcl_ObjCmdProc *xProc;
  } aCmd[] = {
    { "sqlite3_expert_new", test_sqlite3_expert_new },
  };
  int i;

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

  return TCL_OK;
}

#endif







>
>

>












|




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
  }

  sqlite3_free(zCmd);
  sqlite3_free(zErr);
  return rc;
}

#endif  /* ifndef SQLITE_OMIT_VIRTUALTABLE */

int TestExpert_Init(Tcl_Interp *interp){
#ifndef SQLITE_OMIT_VIRTUALTABLE
  struct Cmd {
    const char *zCmd;
    Tcl_ObjCmdProc *xProc;
  } aCmd[] = {
    { "sqlite3_expert_new", test_sqlite3_expert_new },
  };
  int i;

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

#endif
Changes to ext/fts5/fts5_tcl.c.
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
      rc = p->pApi->xSetAuxdata(p->pFts, (void*)((char*)0 + iVal), 0);
      break;
    }
    CASE(15, "xGetAuxdataInt") {
      int iVal;
      int bClear;
      if( Tcl_GetBooleanFromObj(interp, objv[2], &bClear) ) return TCL_ERROR;
      iVal = ((char*)p->pApi->xGetAuxdata(p->pFts, bClear) - (char*)0);
      Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
      break;
    }

    CASE(16, "xPhraseForeach") {
      int iPhrase;
      int iCol;







|







429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
      rc = p->pApi->xSetAuxdata(p->pFts, (void*)((char*)0 + iVal), 0);
      break;
    }
    CASE(15, "xGetAuxdataInt") {
      int iVal;
      int bClear;
      if( Tcl_GetBooleanFromObj(interp, objv[2], &bClear) ) return TCL_ERROR;
      iVal = (int)((char*)p->pApi->xGetAuxdata(p->pFts, bClear) - (char*)0);
      Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
      break;
    }

    CASE(16, "xPhraseForeach") {
      int iPhrase;
      int iCol;
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
      Fts5PhraseIter iter;

      if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR;
      zColvar = Tcl_GetString(objv[3]);

      rc = p->pApi->xPhraseFirstColumn(p->pFts, iPhrase, &iter, &iCol);
      if( rc!=SQLITE_OK ){
        Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
        return TCL_ERROR;
      }
      for( ; iCol>=0; p->pApi->xPhraseNextColumn(p->pFts, &iter, &iCol)){
        Tcl_SetVar2Ex(interp, zColvar, 0, Tcl_NewIntObj(iCol), 0);
        rc = Tcl_EvalObjEx(interp, pScript, 0);
        if( rc==TCL_CONTINUE ) rc = TCL_OK;
        if( rc!=TCL_OK ){







|







478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
      Fts5PhraseIter iter;

      if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR;
      zColvar = Tcl_GetString(objv[3]);

      rc = p->pApi->xPhraseFirstColumn(p->pFts, iPhrase, &iter, &iCol);
      if( rc!=SQLITE_OK ){
        Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
        return TCL_ERROR;
      }
      for( ; iCol>=0; p->pApi->xPhraseNextColumn(p->pFts, &iter, &iCol)){
        Tcl_SetVar2Ex(interp, zColvar, 0, Tcl_NewIntObj(iCol), 0);
        rc = Tcl_EvalObjEx(interp, pScript, 0);
        if( rc==TCL_CONTINUE ) rc = TCL_OK;
        if( rc!=TCL_OK ){
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
        "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 TCL_OK;

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

static void f5tDelTokenizer(void *pCtx){







|







920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
        "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;
}

static void f5tDelTokenizer(void *pCtx){
Changes to ext/fts5/test/fts5fault6.test.
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
  sqlite3_fts5_register_matchinfo db
  db func mit mit
} -body {
  db eval { 
    SELECT rowid, mit(matchinfo(t1, 'x')) FROM t1 WHERE t1 MATCH 'a AND c'
  }
} -test {
  faultsim_test_result [list 0 $::res]
}

do_faultsim_test 5.3 -faults oom* -prep {
  faultsim_restore_and_reopen
  sqlite3_fts5_create_tokenizer db tcl tcl_create
} -body {
  db eval { 
    SELECT count(*) FROM t1 WHERE t1 MATCH 'd AND e AND f'
  }
} -test {
  faultsim_test_result {0 29}
}

do_faultsim_test 5.4 -faults oom* -prep {
  faultsim_restore_and_reopen
  sqlite3_fts5_create_tokenizer db tcl tcl_create
} -body {
  db eval { 
    SELECT count(*) FROM t1 WHERE t1 MATCH 'x + e'
  }
} -test {
  faultsim_test_result {0 1}
}

#-------------------------------------------------------------------------
catch { db close }
do_faultsim_test 6 -faults oom* -prep {
  sqlite_orig db test.db
  sqlite3_db_config_lookaside db 0 0 0







|










|










|







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
  sqlite3_fts5_register_matchinfo db
  db func mit mit
} -body {
  db eval { 
    SELECT rowid, mit(matchinfo(t1, 'x')) FROM t1 WHERE t1 MATCH 'a AND c'
  }
} -test {
  faultsim_test_result [list 0 $::res] {1 {SQL logic error}}
}

do_faultsim_test 5.3 -faults oom* -prep {
  faultsim_restore_and_reopen
  sqlite3_fts5_create_tokenizer db tcl tcl_create
} -body {
  db eval { 
    SELECT count(*) FROM t1 WHERE t1 MATCH 'd AND e AND f'
  }
} -test {
  faultsim_test_result {0 29} {1 {SQL logic error}}
}

do_faultsim_test 5.4 -faults oom* -prep {
  faultsim_restore_and_reopen
  sqlite3_fts5_create_tokenizer db tcl tcl_create
} -body {
  db eval { 
    SELECT count(*) FROM t1 WHERE t1 MATCH 'x + e'
  }
} -test {
  faultsim_test_result {0 1} {1 {SQL logic error}}
}

#-------------------------------------------------------------------------
catch { db close }
do_faultsim_test 6 -faults oom* -prep {
  sqlite_orig db test.db
  sqlite3_db_config_lookaside db 0 0 0
Changes to ext/fts5/test/fts5fault9.test.
20
21
22
23
24
25
26


27
28
29
30
31
32
33
ifcapable !fts5 {
  finish_test
  return
}

foreach_detail_mode $testprefix {



fts5_aux_test_functions db

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
  WITH seq(s) AS ( SELECT 1 UNION ALL SELECT s+1 FROM seq WHERE s<50)
  INSERT INTO t1 SELECT 'x x x y y y', 'a b c d e f' FROM seq;







>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
ifcapable !fts5 {
  finish_test
  return
}

foreach_detail_mode $testprefix {

if {"%DETAIL%" != "none"} continue

fts5_aux_test_functions db

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
  WITH seq(s) AS ( SELECT 1 UNION ALL SELECT s+1 FROM seq WHERE s<50)
  INSERT INTO t1 SELECT 'x x x y y y', 'a b c d e f' FROM seq;
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108

109
110
111
112
113
114
115
  INSERT INTO t4 VALUES('c1 c2 c3', 'c4 c5 c6', 'c7 c8 c9');
}

do_faultsim_test 4.1 -faults oom-t* -body {
  execsql { SELECT rowid, fts5_test_collist(t4) FROM t4('2') }
} -test {
  faultsim_test_result \
      {0 {1 {0.0 0.1 0.2} 2 {0.0 0.1 0.2} 3 {0.0 0.1 0.2}}} {1 SQLITE_NOMEM}

}

do_faultsim_test 4.2 -faults oom-t* -body {
  execsql { SELECT rowid, fts5_test_collist(t4) FROM t4('a5 OR b5 OR c5') }
} -test {
  faultsim_test_result \
      {0 {4 {0.0 0.1 0.2} 5 {1.0 1.1 1.2} 6 {2.0 2.1 2.2}}} {1 SQLITE_NOMEM}

}


#-------------------------------------------------------------------------
# An OOM within an "ORDER BY rank" query.
#
db func rnddoc fts5_rnddoc 







|
>






|
>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  INSERT INTO t4 VALUES('c1 c2 c3', 'c4 c5 c6', 'c7 c8 c9');
}

do_faultsim_test 4.1 -faults oom-t* -body {
  execsql { SELECT rowid, fts5_test_collist(t4) FROM t4('2') }
} -test {
  faultsim_test_result \
      {0 {1 {0.0 0.1 0.2} 2 {0.0 0.1 0.2} 3 {0.0 0.1 0.2}}} \
      {1 SQLITE_NOMEM} {1 SQLITE_ERROR} {1 {SQL logic error}}
}

do_faultsim_test 4.2 -faults oom-t* -body {
  execsql { SELECT rowid, fts5_test_collist(t4) FROM t4('a5 OR b5 OR c5') }
} -test {
  faultsim_test_result \
      {0 {4 {0.0 0.1 0.2} 5 {1.0 1.1 1.2} 6 {2.0 2.1 2.2}}} \
      {1 SQLITE_NOMEM} {1 SQLITE_ERROR} {1 {SQL logic error}}
}


#-------------------------------------------------------------------------
# An OOM within an "ORDER BY rank" query.
#
db func rnddoc fts5_rnddoc 
Changes to ext/lsm1/lsm-test/lsmtest.h.
117
118
119
120
121
122
123

124
125
126
127
128
129
130
** Functions in wrapper3.c. This file contains the tdb wrapper for lsm.
** The wrapper for lsm is a bit more involved than the others, as it 
** includes code for a couple of different lsm configurations, and for
** various types of fault injection and robustness testing.
*/
int test_lsm_open(const char*, const char *zFile, int bClear, TestDb **ppDb);
int test_lsm_lomem_open(const char*, const char*, int bClear, TestDb **ppDb);

int test_lsm_zip_open(const char*, const char*, int bClear, TestDb **ppDb);
int test_lsm_small_open(const char*, const char*, int bClear, TestDb **ppDb);
int test_lsm_mt2(const char*, const char *zFile, int bClear, TestDb **ppDb);
int test_lsm_mt3(const char*, const char *zFile, int bClear, TestDb **ppDb);

int tdb_lsm_configure(lsm_db *, const char *);








>







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
** Functions in wrapper3.c. This file contains the tdb wrapper for lsm.
** The wrapper for lsm is a bit more involved than the others, as it 
** includes code for a couple of different lsm configurations, and for
** various types of fault injection and robustness testing.
*/
int test_lsm_open(const char*, const char *zFile, int bClear, TestDb **ppDb);
int test_lsm_lomem_open(const char*, const char*, int bClear, TestDb **ppDb);
int test_lsm_lomem2_open(const char*, const char*, int bClear, TestDb **ppDb);
int test_lsm_zip_open(const char*, const char*, int bClear, TestDb **ppDb);
int test_lsm_small_open(const char*, const char*, int bClear, TestDb **ppDb);
int test_lsm_mt2(const char*, const char *zFile, int bClear, TestDb **ppDb);
int test_lsm_mt3(const char*, const char *zFile, int bClear, TestDb **ppDb);

int tdb_lsm_configure(lsm_db *, const char *);

Changes to ext/lsm1/lsm-test/lsmtest_tdb.c.
717
718
719
720
721
722
723

724
725
726
727
728
729
730
  const char *zName;
  const char *zDefaultDb;
  int (*xOpen)(const char *, const char *zFilename, int bClear, TestDb **ppDb);
} aLib[] = {
  { "sqlite3",      "testdb.sqlite",    sql_open },
  { "lsm_small",    "testdb.lsm_small", test_lsm_small_open },
  { "lsm_lomem",    "testdb.lsm_lomem", test_lsm_lomem_open },

#ifdef HAVE_ZLIB
  { "lsm_zip",      "testdb.lsm_zip",   test_lsm_zip_open },
#endif
  { "lsm",          "testdb.lsm",       test_lsm_open },
#ifdef LSM_MUTEX_PTHREADS
  { "lsm_mt2",      "testdb.lsm_mt2",   test_lsm_mt2 },
  { "lsm_mt3",      "testdb.lsm_mt3",   test_lsm_mt3 },







>







717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  const char *zName;
  const char *zDefaultDb;
  int (*xOpen)(const char *, const char *zFilename, int bClear, TestDb **ppDb);
} aLib[] = {
  { "sqlite3",      "testdb.sqlite",    sql_open },
  { "lsm_small",    "testdb.lsm_small", test_lsm_small_open },
  { "lsm_lomem",    "testdb.lsm_lomem", test_lsm_lomem_open },
  { "lsm_lomem2",   "testdb.lsm_lomem2", test_lsm_lomem2_open },
#ifdef HAVE_ZLIB
  { "lsm_zip",      "testdb.lsm_zip",   test_lsm_zip_open },
#endif
  { "lsm",          "testdb.lsm",       test_lsm_open },
#ifdef LSM_MUTEX_PTHREADS
  { "lsm_mt2",      "testdb.lsm_mt2",   test_lsm_mt2 },
  { "lsm_mt3",      "testdb.lsm_mt3",   test_lsm_mt3 },
Changes to ext/lsm1/lsm-test/lsmtest_tdb3.c.
1028
1029
1030
1031
1032
1033
1034













1035
1036
1037
1038
1039
1040
1041
  const char *zCfg = 
    "page_size=256 block_size=64 autoflush=16 "
    "autocheckpoint=32"
    "mmap=0 "
  ;
  return testLsmOpen(zCfg, zFilename, bClear, ppDb);
}














int test_lsm_zip_open(
  const char *zSpec, 
  const char *zFilename, 
  int bClear, 
  TestDb **ppDb
){







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







1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
  const char *zCfg = 
    "page_size=256 block_size=64 autoflush=16 "
    "autocheckpoint=32"
    "mmap=0 "
  ;
  return testLsmOpen(zCfg, zFilename, bClear, ppDb);
}

int test_lsm_lomem2_open(
  const char *zSpec, 
  const char *zFilename, 
  int bClear, 
  TestDb **ppDb
){
    /* "max_freelist=4 autocheckpoint=32" */
  const char *zCfg = 
    "page_size=512 block_size=64 autoflush=0 mmap=0 "
  ;
  return testLsmOpen(zCfg, zFilename, bClear, ppDb);
}

int test_lsm_zip_open(
  const char *zSpec, 
  const char *zFilename, 
  int bClear, 
  TestDb **ppDb
){
Changes to ext/lsm1/lsm_main.c.
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
    int pgsz = lsmFsPageSize(pDb->pFS);
    int nQuant = LSM_AUTOWORK_QUANT * pgsz;
    int nBefore;
    int nAfter;
    int nDiff;

    if( nQuant>pDb->nTreeLimit ){
      nQuant = pDb->nTreeLimit;
    }

    nBefore = lsmTreeSize(pDb);
    if( bDeleteRange ){
      rc = lsmTreeDelete(pDb, (void *)pKey, nKey, (void *)pVal, nVal);
    }else{
      rc = lsmTreeInsert(pDb, (void *)pKey, nKey, (void *)pVal, nVal);







|







679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
    int pgsz = lsmFsPageSize(pDb->pFS);
    int nQuant = LSM_AUTOWORK_QUANT * pgsz;
    int nBefore;
    int nAfter;
    int nDiff;

    if( nQuant>pDb->nTreeLimit ){
      nQuant = LSM_MAX(pDb->nTreeLimit, pgsz);
    }

    nBefore = lsmTreeSize(pDb);
    if( bDeleteRange ){
      rc = lsmTreeDelete(pDb, (void *)pKey, nKey, (void *)pVal, nVal);
    }else{
      rc = lsmTreeInsert(pDb, (void *)pKey, nKey, (void *)pVal, nVal);
Changes to ext/lsm1/lsm_sorted.c.
5248
5249
5250
5251
5252
5253
5254
5255
5256

5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
    nRem -= nPg;
    if( nPg ) bDirty = 1;
  }

  /* If the in-memory part of the free-list is too large, write a new 
  ** top-level containing just the in-memory free-list entries to disk. */
  if( rc==LSM_OK && pDb->pWorker->freelist.nEntry > pDb->nMaxFreelist ){
    int nPg = 0;
    while( rc==LSM_OK && lsmDatabaseFull(pDb) ){

      rc = sortedWork(pDb, 16, nMerge, 1, &nPg);
      nRem -= nPg;
    }
    if( rc==LSM_OK ){
      rc = sortedNewFreelistOnly(pDb);
    }
    nRem -= nPg;
    if( nPg ) bDirty = 1;
  }

  if( rc==LSM_OK ){
    *pnWrite = (nMax - nRem);
    *pbCkpt = (bCkpt && nRem<=0);
    if( nMerge==1 && pDb->nAutockpt>0 && *pnWrite>0
     && pWorker->pLevel 







<

>






<
|







5248
5249
5250
5251
5252
5253
5254

5255
5256
5257
5258
5259
5260
5261
5262

5263
5264
5265
5266
5267
5268
5269
5270
    nRem -= nPg;
    if( nPg ) bDirty = 1;
  }

  /* If the in-memory part of the free-list is too large, write a new 
  ** top-level containing just the in-memory free-list entries to disk. */
  if( rc==LSM_OK && pDb->pWorker->freelist.nEntry > pDb->nMaxFreelist ){

    while( rc==LSM_OK && lsmDatabaseFull(pDb) ){
      int nPg = 0;
      rc = sortedWork(pDb, 16, nMerge, 1, &nPg);
      nRem -= nPg;
    }
    if( rc==LSM_OK ){
      rc = sortedNewFreelistOnly(pDb);
    }

    bDirty = 1;
  }

  if( rc==LSM_OK ){
    *pnWrite = (nMax - nRem);
    *pbCkpt = (bCkpt && nRem<=0);
    if( nMerge==1 && pDb->nAutockpt>0 && *pnWrite>0
     && pWorker->pLevel 
Changes to ext/misc/README.md.
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











as follows:

  *  **carray.c** &mdash;  This module implements the
     [carray](https://www.sqlite.org/carray.html) table-valued function.
     It is a good example of how to go about implementing a custom
     [table-valued function](https://www.sqlite.org/vtab.html#tabfunc2).





  *  **dbdump.c** &mdash;  This is not actually a loadable extension, but
     rather a library that implements an approximate equivalent to the
     ".dump" command of the
     [command-line shell](https://www.sqlite.org/cli.html).






  *  **memvfs.c** &mdash;  This file implements a custom
     [VFS](https://www.sqlite.org/vfs.html) that stores an entire database
     file in a single block of RAM.  It serves as a good example of how
     to implement a simple custom VFS.

  *  **rot13.c** &mdash;  This file implements the very simple rot13()
     substitution function.  This file makes a good template for implementing
     new custom SQL functions for SQLite.

  *  **series.c** &mdash;  This is an implementation of the
     "generate_series" [virtual table](https://www.sqlite.org/vtab.html).
     It can make a good template for new custom virtual table implementations.

  *  **shathree.c** &mdash;  An implementation of the sha3() and
     sha3_query() SQL functions.  The file is named "shathree.c" instead
     of "sha3.c" because the default entry point names in SQLite are based
     on the source filename with digits removed, so if we used the name
     "sha3.c" then the entry point would conflict with the prior "sha1.c"
     extension.


















>
>
>
>




>
>
>
>
>




















>
>
>
>
>
>
>
>
>
>
>
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
as follows:

  *  **carray.c** &mdash;  This module implements the
     [carray](https://www.sqlite.org/carray.html) table-valued function.
     It is a good example of how to go about implementing a custom
     [table-valued function](https://www.sqlite.org/vtab.html#tabfunc2).

  *  **csv.c** &mdash;  A [virtual table](https://sqlite.org/vtab.html)
     for reading 
     [Comma-Separated-Value (CSV) files](https://en.wikipedia.org/wiki/Comma-separated_values).

  *  **dbdump.c** &mdash;  This is not actually a loadable extension, but
     rather a library that implements an approximate equivalent to the
     ".dump" command of the
     [command-line shell](https://www.sqlite.org/cli.html).

  *  **json1.c** &mdash;  Various SQL functions and table-valued functions
     for processing JSON.  This extension is already built into the
     [SQLite amalgamation](https://sqlite.org/amalgamation.html).  See
     <https://sqlite.org/json1.html> for additional information.

  *  **memvfs.c** &mdash;  This file implements a custom
     [VFS](https://www.sqlite.org/vfs.html) that stores an entire database
     file in a single block of RAM.  It serves as a good example of how
     to implement a simple custom VFS.

  *  **rot13.c** &mdash;  This file implements the very simple rot13()
     substitution function.  This file makes a good template for implementing
     new custom SQL functions for SQLite.

  *  **series.c** &mdash;  This is an implementation of the
     "generate_series" [virtual table](https://www.sqlite.org/vtab.html).
     It can make a good template for new custom virtual table implementations.

  *  **shathree.c** &mdash;  An implementation of the sha3() and
     sha3_query() SQL functions.  The file is named "shathree.c" instead
     of "sha3.c" because the default entry point names in SQLite are based
     on the source filename with digits removed, so if we used the name
     "sha3.c" then the entry point would conflict with the prior "sha1.c"
     extension.

  *  **unionvtab.c** &mdash; Implementation of the unionvtab and
     [swarmvtab](https://sqlite.org/swarmvtab.html) virtual tables.
     These virtual tables allow a single
     large table to be spread out across multiple database files.  In the
     case of swarmvtab, the individual database files can be attached on
     demand.

  *  **zipfile.c** &mdash;  A [virtual table](https://sqlite.org/vtab.html)
     that can read and write a 
     [ZIP archive](https://en.wikipedia.org/wiki/Zip_%28file_format%29).
Added ext/misc/appendvfs.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
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
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
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
/*
** 2017-10-20
**
** 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 a VFS shim that allows an SQLite database to be
** appended onto the end of some other file, such as an executable.
**
** A special record must appear at the end of the file that identifies the
** file as an appended database and provides an offset to page 1.  For
** best performance page 1 should be located at a disk page boundary, though
** that is not required.
**
** When opening a database using this VFS, the connection might treat
** the file as an ordinary SQLite database, or it might treat is as a
** database appended onto some other file.  Here are the rules:
**
**  (1)  When opening a new empty file, that file is treated as an ordinary
**       database.
**
**  (2)  When opening a file that begins with the standard SQLite prefix
**       string "SQLite format 3", that file is treated as an ordinary
**       database.
**
**  (3)  When opening a file that ends with the appendvfs trailer string
**       "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended
**       database.
**
**  (4)  If none of the above apply and the SQLITE_OPEN_CREATE flag is
**       set, then a new database is appended to the already existing file.
**
**  (5)  Otherwise, SQLITE_CANTOPEN is returned.
**
** To avoid unnecessary complications with the PENDING_BYTE, the size of
** the file containing the database is limited to 1GB.  This VFS will refuse
** to read or write past the 1GB mark.  This restriction might be lifted in
** future versions.  For now, if you need a large database, then keep the
** database in a separate file.
**
** If the file being opened is not an appended database, then this shim is
** a pass-through into the default underlying VFS.
**/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <string.h>
#include <assert.h>

/* The append mark at the end of the database is:
**
**     Start-Of-SQLite3-NNNNNNNN
**     123456789 123456789 12345
**
** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
** the offset to page 1.
*/
#define APND_MARK_PREFIX     "Start-Of-SQLite3-"
#define APND_MARK_PREFIX_SZ  17
#define APND_MARK_SIZE       25

/*
** Maximum size of the combined prefix + database + append-mark.  This
** must be less than 0x40000000 to avoid locking issues on Windows.
*/
#define APND_MAX_SIZE  (65536*15259)

/*
** Forward declaration of objects used by this utility
*/
typedef struct sqlite3_vfs ApndVfs;
typedef struct ApndFile ApndFile;

/* Access to a lower-level VFS that (might) implement dynamic loading,
** access to randomness, etc.
*/
#define ORIGVFS(p)  ((sqlite3_vfs*)((p)->pAppData))
#define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))

/* An open file */
struct ApndFile {
  sqlite3_file base;              /* IO methods */
  sqlite3_int64 iPgOne;           /* File offset to page 1 */
  sqlite3_int64 iMark;            /* Start of the append-mark */
};

/*
** Methods for ApndFile
*/
static int apndClose(sqlite3_file*);
static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int apndWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int apndTruncate(sqlite3_file*, sqlite3_int64 size);
static int apndSync(sqlite3_file*, int flags);
static int apndFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int apndLock(sqlite3_file*, int);
static int apndUnlock(sqlite3_file*, int);
static int apndCheckReservedLock(sqlite3_file*, int *pResOut);
static int apndFileControl(sqlite3_file*, int op, void *pArg);
static int apndSectorSize(sqlite3_file*);
static int apndDeviceCharacteristics(sqlite3_file*);
static int apndShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
static int apndShmLock(sqlite3_file*, int offset, int n, int flags);
static void apndShmBarrier(sqlite3_file*);
static int apndShmUnmap(sqlite3_file*, int deleteFlag);
static int apndFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
static int apndUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);

/*
** Methods for ApndVfs
*/
static int apndOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int apndDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int apndAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int apndFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *apndDlOpen(sqlite3_vfs*, const char *zFilename);
static void apndDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
static void apndDlClose(sqlite3_vfs*, void*);
static int apndRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int apndSleep(sqlite3_vfs*, int microseconds);
static int apndCurrentTime(sqlite3_vfs*, double*);
static int apndGetLastError(sqlite3_vfs*, int, char *);
static int apndCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static int apndSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
static sqlite3_syscall_ptr apndGetSystemCall(sqlite3_vfs*, const char *z);
static const char *apndNextSystemCall(sqlite3_vfs*, const char *zName);

static sqlite3_vfs apnd_vfs = {
  3,                            /* iVersion (set when registered) */
  0,                            /* szOsFile (set when registered) */
  1024,                         /* mxPathname */
  0,                            /* pNext */
  "apndvfs",                    /* zName */
  0,                            /* pAppData (set when registered) */ 
  apndOpen,                     /* xOpen */
  apndDelete,                   /* xDelete */
  apndAccess,                   /* xAccess */
  apndFullPathname,             /* xFullPathname */
  apndDlOpen,                   /* xDlOpen */
  apndDlError,                  /* xDlError */
  apndDlSym,                    /* xDlSym */
  apndDlClose,                  /* xDlClose */
  apndRandomness,               /* xRandomness */
  apndSleep,                    /* xSleep */
  apndCurrentTime,              /* xCurrentTime */
  apndGetLastError,             /* xGetLastError */
  apndCurrentTimeInt64,         /* xCurrentTimeInt64 */
  apndSetSystemCall,            /* xSetSystemCall */
  apndGetSystemCall,            /* xGetSystemCall */
  apndNextSystemCall            /* xNextSystemCall */
};

static const sqlite3_io_methods apnd_io_methods = {
  3,                              /* iVersion */
  apndClose,                      /* xClose */
  apndRead,                       /* xRead */
  apndWrite,                      /* xWrite */
  apndTruncate,                   /* xTruncate */
  apndSync,                       /* xSync */
  apndFileSize,                   /* xFileSize */
  apndLock,                       /* xLock */
  apndUnlock,                     /* xUnlock */
  apndCheckReservedLock,          /* xCheckReservedLock */
  apndFileControl,                /* xFileControl */
  apndSectorSize,                 /* xSectorSize */
  apndDeviceCharacteristics,      /* xDeviceCharacteristics */
  apndShmMap,                     /* xShmMap */
  apndShmLock,                    /* xShmLock */
  apndShmBarrier,                 /* xShmBarrier */
  apndShmUnmap,                   /* xShmUnmap */
  apndFetch,                      /* xFetch */
  apndUnfetch                     /* xUnfetch */
};



/*
** Close an apnd-file.
*/
static int apndClose(sqlite3_file *pFile){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xClose(pFile);
}

/*
** Read data from an apnd-file.
*/
static int apndRead(
  sqlite3_file *pFile, 
  void *zBuf, 
  int iAmt, 
  sqlite_int64 iOfst
){
  ApndFile *p = (ApndFile *)pFile;
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne);
}

/*
** Add the append-mark onto the end of the file.
*/
static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){
  int i;
  unsigned char a[APND_MARK_SIZE];
  memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
  for(i=0; i<8; i++){
    a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff;
  }
  return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark);
}

/*
** Write data to an apnd-file.
*/
static int apndWrite(
  sqlite3_file *pFile,
  const void *zBuf,
  int iAmt,
  sqlite_int64 iOfst
){
  int rc;
  ApndFile *p = (ApndFile *)pFile;
  pFile = ORIGFILE(pFile);
  if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL;
  rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne);
  if( rc==SQLITE_OK &&  iOfst + iAmt + p->iPgOne > p->iMark ){
    sqlite3_int64 sz = 0;
    rc = pFile->pMethods->xFileSize(pFile, &sz);
    if( rc==SQLITE_OK ){
      p->iMark = sz - APND_MARK_SIZE;
      if( iOfst + iAmt + p->iPgOne > p->iMark ){
        p->iMark = p->iPgOne + iOfst + iAmt;
        rc = apndWriteMark(p, pFile);
      }
    }
  }
  return rc;
}

/*
** Truncate an apnd-file.
*/
static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){
  int rc;
  ApndFile *p = (ApndFile *)pFile;
  pFile = ORIGFILE(pFile);
  rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE);
  if( rc==SQLITE_OK ){
    p->iMark = p->iPgOne+size;
    rc = apndWriteMark(p, pFile);
  }
  return rc;
}

/*
** Sync an apnd-file.
*/
static int apndSync(sqlite3_file *pFile, int flags){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xSync(pFile, flags);
}

/*
** Return the current file-size of an apnd-file.
*/
static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
  ApndFile *p = (ApndFile *)pFile;
  int rc;
  pFile = ORIGFILE(p);
  rc = pFile->pMethods->xFileSize(pFile, pSize);
  if( rc==SQLITE_OK && p->iPgOne ){
    *pSize -= p->iPgOne + APND_MARK_SIZE;
  }
  return rc;
}

/*
** Lock an apnd-file.
*/
static int apndLock(sqlite3_file *pFile, int eLock){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xLock(pFile, eLock);
}

/*
** Unlock an apnd-file.
*/
static int apndUnlock(sqlite3_file *pFile, int eLock){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xUnlock(pFile, eLock);
}

/*
** Check if another file-handle holds a RESERVED lock on an apnd-file.
*/
static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
}

/*
** File control method. For custom operations on an apnd-file.
*/
static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){
  ApndFile *p = (ApndFile *)pFile;
  int rc;
  pFile = ORIGFILE(pFile);
  rc = pFile->pMethods->xFileControl(pFile, op, pArg);
  if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
    *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg);
  }
  return rc;
}

/*
** Return the sector-size in bytes for an apnd-file.
*/
static int apndSectorSize(sqlite3_file *pFile){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xSectorSize(pFile);
}

/*
** Return the device characteristic flags supported by an apnd-file.
*/
static int apndDeviceCharacteristics(sqlite3_file *pFile){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xDeviceCharacteristics(pFile);
}

/* Create a shared memory file mapping */
static int apndShmMap(
  sqlite3_file *pFile,
  int iPg,
  int pgsz,
  int bExtend,
  void volatile **pp
){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
}

/* Perform locking on a shared-memory segment */
static int apndShmLock(sqlite3_file *pFile, int offset, int n, int flags){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xShmLock(pFile,offset,n,flags);
}

/* Memory barrier operation on shared memory */
static void apndShmBarrier(sqlite3_file *pFile){
  pFile = ORIGFILE(pFile);
  pFile->pMethods->xShmBarrier(pFile);
}

/* Unmap a shared memory segment */
static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
}

/* Fetch a page of a memory-mapped file */
static int apndFetch(
  sqlite3_file *pFile,
  sqlite3_int64 iOfst,
  int iAmt,
  void **pp
){
  ApndFile *p = (ApndFile *)pFile;
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
}

/* Release a memory-mapped page */
static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
  ApndFile *p = (ApndFile *)pFile;
  pFile = ORIGFILE(pFile);
  return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage);
}

/*
** Check to see if the file is an ordinary SQLite database file.
*/
static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
  int rc;
  char zHdr[16];
  static const char aSqliteHdr[] = "SQLite format 3";
  if( sz<512 ) return 0;
  rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0);
  if( rc ) return 0;
  return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0;
}

/*
** Try to read the append-mark off the end of a file.  Return the
** start of the appended database if the append-mark is present.  If
** there is no append-mark, return -1;
*/
static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){
  int rc, i;
  sqlite3_int64 iMark;
  unsigned char a[APND_MARK_SIZE];

  if( sz<=APND_MARK_SIZE ) return -1;
  rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE);
  if( rc ) return -1;
  if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1;
  iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56;
  for(i=1; i<8; i++){    
    iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i);
  }
  return iMark;
}

/*
** Open an apnd file handle.
*/
static int apndOpen(
  sqlite3_vfs *pVfs,
  const char *zName,
  sqlite3_file *pFile,
  int flags,
  int *pOutFlags
){
  ApndFile *p;
  sqlite3_file *pSubFile;
  sqlite3_vfs *pSubVfs;
  int rc;
  sqlite3_int64 sz;
  pSubVfs = ORIGVFS(pVfs);
  if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
    return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
  }
  p = (ApndFile*)pFile;
  memset(p, 0, sizeof(*p));
  pSubFile = ORIGFILE(pFile);
  p->base.pMethods = &apnd_io_methods;
  rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
  if( rc ) goto apnd_open_done;
  rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
  if( rc ){
    pSubFile->pMethods->xClose(pSubFile);
    goto apnd_open_done;
  }
  if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){
    memmove(pFile, pSubFile, pSubVfs->szOsFile);
    return SQLITE_OK;
  }
  p->iMark = 0;
  p->iPgOne = apndReadMark(sz, pFile);
  if( p->iPgOne>0 ){
    return SQLITE_OK;
  }
  if( (flags & SQLITE_OPEN_CREATE)==0 ){
    pSubFile->pMethods->xClose(pSubFile);
    rc = SQLITE_CANTOPEN;
  }
  p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff;
apnd_open_done:
  if( rc ) pFile->pMethods = 0;
  return rc;
}

/*
** All other VFS methods are pass-thrus.
*/
static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
}
static int apndAccess(
  sqlite3_vfs *pVfs, 
  const char *zPath, 
  int flags, 
  int *pResOut
){
  return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
}
static int apndFullPathname(
  sqlite3_vfs *pVfs, 
  const char *zPath, 
  int nOut, 
  char *zOut
){
  return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
}
static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){
  return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
}
static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
  ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
}
static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
  return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
}
static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){
  ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
}
static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
  return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
}
static int apndSleep(sqlite3_vfs *pVfs, int nMicro){
  return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
}
static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
  return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
}
static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){
  return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
}
static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
  return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
}
static int apndSetSystemCall(
  sqlite3_vfs *pVfs,
  const char *zName,
  sqlite3_syscall_ptr pCall
){
  return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
}
static sqlite3_syscall_ptr apndGetSystemCall(
  sqlite3_vfs *pVfs,
  const char *zName
){
  return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
}
static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
  return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
}

  
#ifdef _WIN32
__declspec(dllexport)
#endif
/* 
** This routine is called when the extension is loaded.
** Register the new VFS.
*/
int sqlite3_appendvfs_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  sqlite3_vfs *pOrig;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;
  (void)db;
  pOrig = sqlite3_vfs_find(0);
  apnd_vfs.iVersion = pOrig->iVersion;
  apnd_vfs.pAppData = pOrig;
  apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile);
  rc = sqlite3_vfs_register(&apnd_vfs, 0);
#ifdef APPENDVFS_TEST
  if( rc==SQLITE_OK ){
    rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister);
  }
#endif
  if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
  return rc;
}
Changes to ext/misc/btreeinfo.c.
335
336
337
338
339
340
341

342
343
344
345
346
347
348
349
){
  BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  if( i>=BINFO_COLUMN_HASROWID && i<=BINFO_COLUMN_SZPAGE && pCsr->hasRowid<0 ){
    int pgno = sqlite3_column_int(pCsr->pStmt, BINFO_COLUMN_ROOTPAGE+1);
    sqlite3 *db = sqlite3_context_db_handle(ctx);
    int rc = binfoCompute(db, pgno, pCsr);
    if( rc ){

      return rc;
    }
  }
  switch( i ){
    case BINFO_COLUMN_NAME:
    case BINFO_COLUMN_TYPE:
    case BINFO_COLUMN_TBL_NAME:
    case BINFO_COLUMN_ROOTPAGE:







>
|







335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
){
  BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  if( i>=BINFO_COLUMN_HASROWID && i<=BINFO_COLUMN_SZPAGE && pCsr->hasRowid<0 ){
    int pgno = sqlite3_column_int(pCsr->pStmt, BINFO_COLUMN_ROOTPAGE+1);
    sqlite3 *db = sqlite3_context_db_handle(ctx);
    int rc = binfoCompute(db, pgno, pCsr);
    if( rc ){
      pCursor->pVtab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
      return SQLITE_ERROR;
    }
  }
  switch( i ){
    case BINFO_COLUMN_NAME:
    case BINFO_COLUMN_TYPE:
    case BINFO_COLUMN_TBL_NAME:
    case BINFO_COLUMN_ROOTPAGE:
Changes to ext/misc/compress.c.
23
24
25
26
27
28
29















30
31
32
33
34
35
36
**
** The output is a BLOB that begins with a variable-length integer that
** is the input size in bytes (the size of X before compression).  The
** variable-length integer is implemented as 1 to 5 bytes.  There are
** seven bits per integer stored in the lower seven bits of each byte.
** More significant bits occur first.  The most significant bit (0x80)
** is a flag to indicate the end of the integer.















*/
static void compressFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const unsigned char *pIn;







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







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
**
** The output is a BLOB that begins with a variable-length integer that
** is the input size in bytes (the size of X before compression).  The
** variable-length integer is implemented as 1 to 5 bytes.  There are
** seven bits per integer stored in the lower seven bits of each byte.
** More significant bits occur first.  The most significant bit (0x80)
** is a flag to indicate the end of the integer.
**
** This function, SQLAR, and ZIP all use the same "deflate" compression
** algorithm, but each is subtly different:
**
**   *  ZIP uses raw deflate.
**
**   *  SQLAR uses the "zlib format" which is raw deflate with a two-byte
**      algorithm-identification header and a four-byte checksum at the end.
**
**   *  This utility uses the "zlib format" like SQLAR, but adds the variable-
**      length integer uncompressed size value at the beginning.
**
** This function might be extended in the future to support compression
** formats other than deflate, by providing a different algorithm-id
** mark following the variable-length integer size parameter.
*/
static void compressFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const unsigned char *pIn;
Changes to ext/misc/fileio.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
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
/*
** 2014-06-13
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
******************************************************************************
**
** This SQLite extension implements SQL functions readfile() and
** writefile().




























































*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <stdio.h>




















































/*
** Implementation of the "readfile(X)" SQL function.  The entire content
** of the file named X is read and returned as a BLOB.  NULL is returned
** if the file does not exist or is unreadable.
*/
static void readfileFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zName;
  FILE *in;
  long nIn;
  void *pBuf;

  (void)(argc);  /* Unused parameter */
  zName = (const char*)sqlite3_value_text(argv[0]);
  if( zName==0 ) return;
  in = fopen(zName, "rb");

  if( in==0 ) return;





  fseek(in, 0, SEEK_END);







  nIn = ftell(in);













  rewind(in);
  pBuf = sqlite3_malloc( nIn );

  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
    sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);


  }else{





















    sqlite3_free(pBuf);
  }



















































  fclose(in);



























































}

/*
** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
** is written into file X.  The number of bytes written is returned.  Or
** NULL is returned if something goes wrong, such as being unable to open
** file X for writing.
*/
static void writefileFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  FILE *out;
  const char *z;


  sqlite3_int64 rc;
  const char *zFile;






  (void)(argc);  /* Unused parameter */
  zFile = (const char*)sqlite3_value_text(argv[0]);
  if( zFile==0 ) return;






  out = fopen(zFile, "wb");









































































































  if( out==0 ) return;





  z = (const char*)sqlite3_value_blob(argv[1]);







  if( z==0 ){



















































































    rc = 0;





































































































































































































  }else{












    rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);

  }
  fclose(out);




  sqlite3_result_int64(context, rc);























}








#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_fileio_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
                               readfileFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
                                 writefileFunc, 0, 0);
  }







  return rc;
}













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




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












<
<
<
<



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

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

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



|
|
<
<






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


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

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

>
>
>
>
>
>















|


>
>
>
>
>
>
>


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
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
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
601
602
603
604
605
606
607
608
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
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
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
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
/*
** 2014-06-13
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
******************************************************************************
**
** This SQLite extension implements SQL functions readfile() and
** writefile(), and eponymous virtual type "fsdir".
**
** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
**
**   If neither of the optional arguments is present, then this UDF
**   function writes blob DATA to file FILE. If successful, the number
**   of bytes written is returned. If an error occurs, NULL is returned.
**
**   If the first option argument - MODE - is present, then it must
**   be passed an integer value that corresponds to a POSIX mode
**   value (file type + permissions, as returned in the stat.st_mode
**   field by the stat() system call). Three types of files may
**   be written/created:
**
**     regular files:  (mode & 0170000)==0100000
**     symbolic links: (mode & 0170000)==0120000
**     directories:    (mode & 0170000)==0040000
**
**   For a directory, the DATA is ignored. For a symbolic link, it is
**   interpreted as text and used as the target of the link. For a
**   regular file, it is interpreted as a blob and written into the
**   named file. Regardless of the type of file, its permissions are
**   set to (mode & 0777) before returning.
**
**   If the optional MTIME argument is present, then it is interpreted
**   as an integer - the number of seconds since the unix epoch. The
**   modification-time of the target file is set to this value before
**   returning.
**
**   If three or more arguments are passed to this function and an
**   error is encountered, an exception is raised.
**
** READFILE(FILE):
**
**   Read and return the contents of file FILE (type blob) from disk.
**
** FSDIR:
**
**   Used as follows:
**
**     SELECT * FROM fsdir($path [, $dir]);
**
**   Parameter $path is an absolute or relative pathname. If the file that it
**   refers to does not exist, it is an error. If the path refers to a regular
**   file or symbolic link, it returns a single row. Or, if the path refers
**   to a directory, it returns one row for the directory, and one row for each
**   file within the hierarchy rooted at $path.
**
**   Each row has the following columns:
**
**     name:  Path to file or directory (text value).
**     mode:  Value of stat.st_mode for directory entry (an integer).
**     mtime: Value of stat.st_mtime for directory entry (an integer).
**     data:  For a regular file, a blob containing the file data. For a
**            symlink, a text value containing the text of the link. For a
**            directory, NULL.
**
**   If a non-NULL value is specified for the optional $dir parameter and
**   $path is a relative path, then $path is interpreted relative to $dir. 
**   And the paths returned in the "name" column of the table are also 
**   relative to directory $dir.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if !defined(_WIN32) && !defined(WIN32)
#  include <unistd.h>
#  include <dirent.h>
#  include <utime.h>
#  include <sys/time.h>
#else
#  include "windows.h"
#  include <io.h>
#  include <direct.h>
#  include "test_windirent.h"
#  define dirent DIRENT
#  ifndef stat
#    define stat _stat
#  endif
#  define mkdir(path,mode) _mkdir(path)
#  define lstat(path,buf) stat(path,buf)
#endif
#include <time.h>
#include <errno.h>


#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"

/*
** Set the result stored by context ctx to a blob containing the 
** contents of file zName.
*/
static void readFileContents(sqlite3_context *ctx, const char *zName){
  FILE *in;
  long nIn;
  void *pBuf;

  in = fopen(zName, "rb");
  if( in==0 ) return;
  fseek(in, 0, SEEK_END);
  nIn = ftell(in);
  rewind(in);
  pBuf = sqlite3_malloc( nIn );
  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
    sqlite3_result_blob(ctx, pBuf, nIn, sqlite3_free);
  }else{
    sqlite3_free(pBuf);
  }
  fclose(in);
}

/*
** Implementation of the "readfile(X)" SQL function.  The entire content
** of the file named X is read and returned as a BLOB.  NULL is returned
** if the file does not exist or is unreadable.
*/
static void readfileFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zName;




  (void)(argc);  /* Unused parameter */
  zName = (const char*)sqlite3_value_text(argv[0]);
  if( zName==0 ) return;
  readFileContents(context, zName);
}

/*
** Set the error message contained in context ctx to the results of
** vprintf(zFmt, ...).
*/
static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
  char *zMsg = 0;
  va_list ap;
  va_start(ap, zFmt);
  zMsg = sqlite3_vmprintf(zFmt, ap);
  sqlite3_result_error(ctx, zMsg, -1);
  sqlite3_free(zMsg);
  va_end(ap);
}

/*
** Argument zFile is the name of a file that will be created and/or written
** by SQL function writefile(). This function ensures that the directory
** zFile will be written to exists, creating it if required. The permissions
** for any path components created by this function are set to (mode&0777).
**
** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
** SQLITE_OK is returned if the directory is successfully created, or
** SQLITE_ERROR otherwise.
*/
static int makeDirectory(
  const char *zFile,
  mode_t mode
){
  char *zCopy = sqlite3_mprintf("%s", zFile);
  int rc = SQLITE_OK;


  if( zCopy==0 ){
    rc = SQLITE_NOMEM;
  }else{
    int nCopy = (int)strlen(zCopy);
    int i = 1;

    while( rc==SQLITE_OK ){
      struct stat sStat;
      int rc2;

      for(; zCopy[i]!='/' && i<nCopy; i++);
      if( i==nCopy ) break;
      zCopy[i] = '\0';

      rc2 = stat(zCopy, &sStat);
      if( rc2!=0 ){
        if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR;
      }else{
        if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
      }
      zCopy[i] = '/';
      i++;
    }

    sqlite3_free(zCopy);
  }

  return rc;
}

/*
** This function does the work for the writefile() UDF. Refer to 
** header comments at the top of this file for details.
*/
static int writeFile(
  sqlite3_context *pCtx,          /* Context to return bytes written in */
  const char *zFile,              /* File to write */
  sqlite3_value *pData,           /* Data to write */
  mode_t mode,                    /* MODE parameter passed to writefile() */
  sqlite3_int64 mtime             /* MTIME parameter (or -1 to not set time) */
){
#if !defined(_WIN32) && !defined(WIN32)
  if( S_ISLNK(mode) ){
    const char *zTo = (const char*)sqlite3_value_text(pData);
    if( symlink(zTo, zFile)<0 ) return 1;
  }else
#endif
  {
    if( S_ISDIR(mode) ){
      if( mkdir(zFile, mode) ){
        /* The mkdir() call to create the directory failed. This might not
        ** be an error though - if there is already a directory at the same
        ** path and either the permissions already match or can be changed
        ** to do so using chmod(), it is not an error.  */
        struct stat sStat;
        if( errno!=EEXIST
         || 0!=stat(zFile, &sStat)
         || !S_ISDIR(sStat.st_mode)
         || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
        ){
          return 1;
        }
      }
    }else{
      sqlite3_int64 nWrite = 0;
      const char *z;
      int rc = 0;
      FILE *out = fopen(zFile, "wb");
      if( out==0 ) return 1;
      z = (const char*)sqlite3_value_blob(pData);
      if( z ){
        sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
        nWrite = sqlite3_value_bytes(pData);
        if( nWrite!=n ){
          rc = 1;
        }
      }
      fclose(out);
      if( rc==0 && mode && chmod(zFile, mode & 0777) ){
        rc = 1;
      }
      if( rc ) return 2;
      sqlite3_result_int64(pCtx, nWrite);
    }
  }

  if( mtime>=0 ){
#if defined(_WIN32)
    /* Windows */
    FILETIME lastAccess;
    FILETIME lastWrite;
    SYSTEMTIME currentTime;
    LONGLONG intervals;
    HANDLE hFile;
    LPWSTR zUnicodeName;
    extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);

    GetSystemTime(&currentTime);
    SystemTimeToFileTime(&currentTime, &lastAccess);
    intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
    lastWrite.dwLowDateTime = (DWORD)intervals;
    lastWrite.dwHighDateTime = intervals >> 32;
    zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
    hFile = CreateFileW(
      zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
      FILE_FLAG_BACKUP_SEMANTICS, NULL
    );
    sqlite3_free(zUnicodeName);
    if( hFile!=INVALID_HANDLE_VALUE ){
      BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
      CloseHandle(hFile);
      return !bResult;
    }else{
      return 1;
    }
#elif defined(AT_FDCWD) && 0 /* utimensat() is not univerally available */
    /* Recent unix */
    struct timespec times[2];
    times[0].tv_nsec = times[1].tv_nsec = 0;
    times[0].tv_sec = time(0);
    times[1].tv_sec = mtime;
    if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
      return 1;
    }
#else
    /* Legacy unix */
    struct timeval times[2];
    times[0].tv_usec = times[1].tv_usec = 0;
    times[0].tv_sec = time(0);
    times[1].tv_sec = mtime;
    if( utimes(zFile, times) ){
      return 1;
    }
#endif
  }

  return 0;
}

/*
** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.  
** Refer to header comments at the top of this file for details.


*/
static void writefileFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){

  const char *zFile;
  mode_t mode = 0;
  int res;
  sqlite3_int64 mtime = -1;

  if( argc<2 || argc>4 ){
    sqlite3_result_error(context, 
        "wrong number of arguments to function writefile()", -1
    );
    return;
  }

  zFile = (const char*)sqlite3_value_text(argv[0]);
  if( zFile==0 ) return;
  if( argc>=3 ){
    mode = (mode_t)sqlite3_value_int(argv[2]);
  }
  if( argc==4 ){
    mtime = sqlite3_value_int64(argv[3]);
  }

  res = writeFile(context, zFile, argv[1], mode, mtime);
  if( res==1 && errno==ENOENT ){
    if( makeDirectory(zFile, mode)==SQLITE_OK ){
      res = writeFile(context, zFile, argv[1], mode, mtime);
    }
  }

  if( argc>2 && res!=0 ){
    if( S_ISLNK(mode) ){
      ctxErrorMsg(context, "failed to create symlink: %s", zFile);
    }else if( S_ISDIR(mode) ){
      ctxErrorMsg(context, "failed to create directory: %s", zFile);
    }else{
      ctxErrorMsg(context, "failed to write file: %s", zFile);
    }
  }
}

/*
** SQL function:   lsmode(MODE)
**
** Given a numberic st_mode from stat(), convert it into a human-readable
** text string in the style of "ls -l".
*/
static void lsModeFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int i;
  int iMode = sqlite3_value_int(argv[0]);
  char z[16];
  (void)argc;
  if( S_ISLNK(iMode) ){
    z[0] = 'l';
  }else if( S_ISREG(iMode) ){
    z[0] = '-';
  }else if( S_ISDIR(iMode) ){
    z[0] = 'd';
  }else{
    z[0] = '?';
  }
  for(i=0; i<3; i++){
    int m = (iMode >> ((2-i)*3));
    char *a = &z[1 + i*3];
    a[0] = (m & 0x4) ? 'r' : '-';
    a[1] = (m & 0x2) ? 'w' : '-';
    a[2] = (m & 0x1) ? 'x' : '-';
  }
  z[10] = '\0';
  sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
}

#ifndef SQLITE_OMIT_VIRTUALTABLE

/* 
** Cursor type for recursively iterating through a directory structure.
*/
typedef struct fsdir_cursor fsdir_cursor;
typedef struct FsdirLevel FsdirLevel;

struct FsdirLevel {
  DIR *pDir;                 /* From opendir() */
  char *zDir;                /* Name of directory (nul-terminated) */
};

struct fsdir_cursor {
  sqlite3_vtab_cursor base;  /* Base class - must be first */

  int nLvl;                  /* Number of entries in aLvl[] array */
  int iLvl;                  /* Index of current entry */
  FsdirLevel *aLvl;          /* Hierarchy of directories being traversed */

  const char *zBase;
  int nBase;

  struct stat sStat;         /* Current lstat() results */
  char *zPath;               /* Path to current entry */
  sqlite3_int64 iRowid;      /* Current rowid */
};

typedef struct fsdir_tab fsdir_tab;
struct fsdir_tab {
  sqlite3_vtab base;         /* Base class - must be first */
};

/*
** Construct a new fsdir virtual table object.
*/
static int fsdirConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  fsdir_tab *pNew = 0;
  int rc;
  (void)pAux;
  (void)argc;
  (void)argv;
  (void)pzErr;
  rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
  if( rc==SQLITE_OK ){
    pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));
  }
  *ppVtab = (sqlite3_vtab*)pNew;
  return rc;
}

/*
** This method is the destructor for fsdir vtab objects.
*/
static int fsdirDisconnect(sqlite3_vtab *pVtab){
  sqlite3_free(pVtab);
  return SQLITE_OK;
}

/*
** Constructor for a new fsdir_cursor object.
*/
static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
  fsdir_cursor *pCur;
  (void)p;
  pCur = sqlite3_malloc( sizeof(*pCur) );
  if( pCur==0 ) return SQLITE_NOMEM;
  memset(pCur, 0, sizeof(*pCur));
  pCur->iLvl = -1;
  *ppCursor = &pCur->base;
  return SQLITE_OK;
}

/*
** Reset a cursor back to the state it was in when first returned
** by fsdirOpen().
*/
static void fsdirResetCursor(fsdir_cursor *pCur){
  int i;
  for(i=0; i<=pCur->iLvl; i++){
    FsdirLevel *pLvl = &pCur->aLvl[i];
    if( pLvl->pDir ) closedir(pLvl->pDir);
    sqlite3_free(pLvl->zDir);
  }
  sqlite3_free(pCur->zPath);
  pCur->aLvl = 0;
  pCur->zPath = 0;
  pCur->zBase = 0;
  pCur->nBase = 0;
  pCur->iLvl = -1;
  pCur->iRowid = 1;
}

/*
** Destructor for an fsdir_cursor.
*/
static int fsdirClose(sqlite3_vtab_cursor *cur){
  fsdir_cursor *pCur = (fsdir_cursor*)cur;

  fsdirResetCursor(pCur);
  sqlite3_free(pCur->aLvl);
  sqlite3_free(pCur);
  return SQLITE_OK;
}

/*
** Set the error message for the virtual table associated with cursor
** pCur to the results of vprintf(zFmt, ...).
*/
static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
  va_list ap;
  va_start(ap, zFmt);
  pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
  va_end(ap);
}


/*
** Advance an fsdir_cursor to its next row of output.
*/
static int fsdirNext(sqlite3_vtab_cursor *cur){
  fsdir_cursor *pCur = (fsdir_cursor*)cur;
  mode_t m = pCur->sStat.st_mode;

  pCur->iRowid++;
  if( S_ISDIR(m) ){
    /* Descend into this directory */
    int iNew = pCur->iLvl + 1;
    FsdirLevel *pLvl;
    if( iNew>=pCur->nLvl ){
      int nNew = iNew+1;
      int nByte = nNew*sizeof(FsdirLevel);
      FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
      if( aNew==0 ) return SQLITE_NOMEM;
      memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
      pCur->aLvl = aNew;
      pCur->nLvl = nNew;
    }
    pCur->iLvl = iNew;
    pLvl = &pCur->aLvl[iNew];
    
    pLvl->zDir = pCur->zPath;
    pCur->zPath = 0;
    pLvl->pDir = opendir(pLvl->zDir);
    if( pLvl->pDir==0 ){
      fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
      return SQLITE_ERROR;
    }
  }

  while( pCur->iLvl>=0 ){
    FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
    struct dirent *pEntry = readdir(pLvl->pDir);
    if( pEntry ){
      if( pEntry->d_name[0]=='.' ){
       if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
       if( pEntry->d_name[1]=='\0' ) continue;
      }
      sqlite3_free(pCur->zPath);
      pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
      if( pCur->zPath==0 ) return SQLITE_NOMEM;
      if( lstat(pCur->zPath, &pCur->sStat) ){
        fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
        return SQLITE_ERROR;
      }
      return SQLITE_OK;
    }
    closedir(pLvl->pDir);
    sqlite3_free(pLvl->zDir);
    pLvl->pDir = 0;
    pLvl->zDir = 0;
    pCur->iLvl--;
  }

  /* EOF */
  sqlite3_free(pCur->zPath);
  pCur->zPath = 0;
  return SQLITE_OK;
}

/*
** Return values of columns for the row at which the series_cursor
** is currently pointing.
*/
static int fsdirColumn(
  sqlite3_vtab_cursor *cur,   /* The cursor */
  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
  int i                       /* Which column to return */
){
  fsdir_cursor *pCur = (fsdir_cursor*)cur;
  switch( i ){
    case 0: { /* name */
      sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
      break;
    }

    case 1: /* mode */
      sqlite3_result_int64(ctx, pCur->sStat.st_mode);
      break;

    case 2: /* mtime */
      sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
      break;

    case 3: { /* data */
      mode_t m = pCur->sStat.st_mode;
      if( S_ISDIR(m) ){
        sqlite3_result_null(ctx);
#if !defined(_WIN32) && !defined(WIN32)
      }else if( S_ISLNK(m) ){
        char aStatic[64];
        char *aBuf = aStatic;
        int nBuf = 64;
        int n;

        while( 1 ){
          n = readlink(pCur->zPath, aBuf, nBuf);
          if( n<nBuf ) break;
          if( aBuf!=aStatic ) sqlite3_free(aBuf);
          nBuf = nBuf*2;
          aBuf = sqlite3_malloc(nBuf);
          if( aBuf==0 ){
            sqlite3_result_error_nomem(ctx);
            return SQLITE_NOMEM;
          }
        }

        sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
        if( aBuf!=aStatic ) sqlite3_free(aBuf);
#endif
      }else{
        readFileContents(ctx, pCur->zPath);
      }
    }
  }
  return SQLITE_OK;
}

/*
** Return the rowid for the current row. In this implementation, the
** first row returned is assigned rowid value 1, and each subsequent
** row a value 1 more than that of the previous.
*/
static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  fsdir_cursor *pCur = (fsdir_cursor*)cur;
  *pRowid = pCur->iRowid;
  return SQLITE_OK;
}

/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int fsdirEof(sqlite3_vtab_cursor *cur){
  fsdir_cursor *pCur = (fsdir_cursor*)cur;
  return (pCur->zPath==0);
}

/*
** xFilter callback.
*/
static int fsdirFilter(
  sqlite3_vtab_cursor *cur, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  const char *zDir = 0;
  fsdir_cursor *pCur = (fsdir_cursor*)cur;
  (void)idxStr;
  fsdirResetCursor(pCur);

  if( idxNum==0 ){
    fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
    return SQLITE_ERROR;
  }

  assert( argc==idxNum && (argc==1 || argc==2) );
  zDir = (const char*)sqlite3_value_text(argv[0]);
  if( zDir==0 ){
    fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
    return SQLITE_ERROR;
  }
  if( argc==2 ){
    pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
  }
  if( pCur->zBase ){
    pCur->nBase = (int)strlen(pCur->zBase)+1;
    pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
  }else{
    pCur->zPath = sqlite3_mprintf("%s", zDir);
  }

  if( pCur->zPath==0 ){
    return SQLITE_NOMEM;
  }
  if( lstat(pCur->zPath, &pCur->sStat) ){
    fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
    return SQLITE_ERROR;
  }

  return SQLITE_OK;
}

/*
** SQLite will invoke this method one or more times while planning a query
** that uses the generate_series virtual table.  This routine needs to create
** a query plan for each invocation and compute an estimated cost for that
** plan.
**
** In this implementation idxNum is used to represent the
** query plan.  idxStr is unused.
**
** The query plan is represented by bits in idxNum:
**
**  (1)  start = $value  -- constraint exists
**  (2)  stop = $value   -- constraint exists
**  (4)  step = $value   -- constraint exists
**  (8)  output in descending order
*/
static int fsdirBestIndex(
  sqlite3_vtab *tab,
  sqlite3_index_info *pIdxInfo
){
  int i;                 /* Loop over constraints */
  int idx4 = -1;
  int idx5 = -1;
  const struct sqlite3_index_constraint *pConstraint;

  (void)tab;
  pConstraint = pIdxInfo->aConstraint;
  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    if( pConstraint->usable==0 ) continue;
    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    if( pConstraint->iColumn==4 ) idx4 = i;
    if( pConstraint->iColumn==5 ) idx5 = i;
  }

  if( idx4<0 ){
    pIdxInfo->idxNum = 0;
    pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
  }else{
    pIdxInfo->aConstraintUsage[idx4].omit = 1;
    pIdxInfo->aConstraintUsage[idx4].argvIndex = 1;
    if( idx5>=0 ){
      pIdxInfo->aConstraintUsage[idx5].omit = 1;
      pIdxInfo->aConstraintUsage[idx5].argvIndex = 2;
      pIdxInfo->idxNum = 2;
      pIdxInfo->estimatedCost = 10.0;
    }else{
      pIdxInfo->idxNum = 1;
      pIdxInfo->estimatedCost = 100.0;
    }
  }

  return SQLITE_OK;
}

/*
** Register the "fsdir" virtual table.
*/
static int fsdirRegister(sqlite3 *db){
  static sqlite3_module fsdirModule = {
    0,                         /* iVersion */
    0,                         /* xCreate */
    fsdirConnect,              /* xConnect */
    fsdirBestIndex,            /* xBestIndex */
    fsdirDisconnect,           /* xDisconnect */
    0,                         /* xDestroy */
    fsdirOpen,                 /* xOpen - open a cursor */
    fsdirClose,                /* xClose - close a cursor */
    fsdirFilter,               /* xFilter - configure scan constraints */
    fsdirNext,                 /* xNext - advance a cursor */
    fsdirEof,                  /* xEof - check for end of scan */
    fsdirColumn,               /* xColumn - read data */
    fsdirRowid,                /* xRowid - read data */
    0,                         /* xUpdate */
    0,                         /* xBegin */
    0,                         /* xSync */
    0,                         /* xCommit */
    0,                         /* xRollback */
    0,                         /* xFindMethod */
    0,                         /* xRename */
    0,                         /* xSavepoint */
    0,                         /* xRelease */
    0                          /* xRollbackTo */
  };

  int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
  return rc;
}
#else         /* SQLITE_OMIT_VIRTUALTABLE */
# define fsdirRegister(x) SQLITE_OK
#endif

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_fileio_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
                               readfileFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
                                 writefileFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
                                 lsModeFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = fsdirRegister(db);
  }
  return rc;
}
Added ext/misc/sqlar.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
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
/*
** 2017-12-17
**
** 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.
**
******************************************************************************
**
** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
** for working with sqlar archives and used by the shell tool's built-in
** sqlar support.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <zlib.h>

/*
** Implementation of the "sqlar_compress(X)" SQL function.
**
** If the type of X is SQLITE_BLOB, and compressing that blob using
** zlib utility function compress() yields a smaller blob, return the
** compressed blob. Otherwise, return a copy of X.
**
** SQLar uses the "zlib format" for compressed content.  The zlib format
** contains a two-byte identification header and a four-byte checksum at
** the end.  This is different from ZIP which uses the raw deflate format.
**
** Future enhancements to SQLar might add support for new compression formats.
** If so, those new formats will be identified by alternative headers in the
** compressed data.
*/
static void sqlarCompressFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  assert( argc==1 );
  if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
    const Bytef *pData = sqlite3_value_blob(argv[0]);
    uLong nData = sqlite3_value_bytes(argv[0]);
    uLongf nOut = compressBound(nData);
    Bytef *pOut;

    pOut = (Bytef*)sqlite3_malloc(nOut);
    if( pOut==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }else{
      if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
        sqlite3_result_error(context, "error in compress()", -1);
      }else if( nOut<nData ){
        sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
      }else{
        sqlite3_result_value(context, argv[0]);
      }
      sqlite3_free(pOut);
    }
  }else{
    sqlite3_result_value(context, argv[0]);
  }
}

/*
** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
**
** Parameter SZ is interpreted as an integer. If it is less than or
** equal to zero, then this function returns a copy of X. Or, if
** SZ is equal to the size of X when interpreted as a blob, also
** return a copy of X. Otherwise, decompress blob X using zlib
** utility function uncompress() and return the results (another
** blob).
*/
static void sqlarUncompressFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  uLong nData;
  uLongf sz;

  assert( argc==2 );
  sz = sqlite3_value_int(argv[1]);

  if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
    sqlite3_result_value(context, argv[0]);
  }else{
    const Bytef *pData= sqlite3_value_blob(argv[0]);
    Bytef *pOut = sqlite3_malloc(sz);
    if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
      sqlite3_result_error(context, "error in uncompress()", -1);
    }else{
      sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
    }
    sqlite3_free(pOut);
  }
}


#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_sqlar_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
                               sqlarCompressFunc, 0, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
                                 sqlarUncompressFunc, 0, 0);
  }
  return rc;
}
Changes to ext/misc/unionvtab.c.
480
481
482
483
484
485
486

487

488
489
490
491
492
493
494
495
496
497
498
499
500
501
*/
static int unionDisconnect(sqlite3_vtab *pVtab){
  if( pVtab ){
    UnionTab *pTab = (UnionTab*)pVtab;
    int i;
    for(i=0; i<pTab->nSrc; i++){
      UnionSrc *pSrc = &pTab->aSrc[i];

      if( pSrc->db ){

        unionInvokeOpenClose(pTab, pSrc, 1, 0);
      }
      sqlite3_free(pSrc->zDb);
      sqlite3_free(pSrc->zTab);
      sqlite3_free(pSrc->zFile);
      sqlite3_free(pSrc->zContext);
      sqlite3_close(pSrc->db);
    }
    sqlite3_finalize(pTab->pNotFound);
    sqlite3_finalize(pTab->pOpenClose);
    sqlite3_free(pTab->zSourceStr);
    sqlite3_free(pTab->aSrc);
    sqlite3_free(pTab);
  }







>
|
>






<







480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495

496
497
498
499
500
501
502
*/
static int unionDisconnect(sqlite3_vtab *pVtab){
  if( pVtab ){
    UnionTab *pTab = (UnionTab*)pVtab;
    int i;
    for(i=0; i<pTab->nSrc; i++){
      UnionSrc *pSrc = &pTab->aSrc[i];
      int bHaveSrcDb = (pSrc->db!=0);
      sqlite3_close(pSrc->db);
      if( bHaveSrcDb ){
        unionInvokeOpenClose(pTab, pSrc, 1, 0);
      }
      sqlite3_free(pSrc->zDb);
      sqlite3_free(pSrc->zTab);
      sqlite3_free(pSrc->zFile);
      sqlite3_free(pSrc->zContext);

    }
    sqlite3_finalize(pTab->pNotFound);
    sqlite3_finalize(pTab->pOpenClose);
    sqlite3_free(pTab->zSourceStr);
    sqlite3_free(pTab->aSrc);
    sqlite3_free(pTab);
  }
Added ext/misc/zipfile.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
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
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
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
601
602
603
604
605
606
607
608
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
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
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
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
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
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
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
977
978
979
980
981
982
983
984
985
986
987
988
989
990
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
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
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
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
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
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
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
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
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
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
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
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
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
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
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
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
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
/*
** 2017-12-26
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file implements a virtual table for reading and writing ZIP archive
** files.
**
** Usage example:
**
**     SELECT name, sz, datetime(mtime,'unixepoch') FROM zipfile($filename);
**
** Current limitations:
**
**    *  No support for encryption
**    *  No support for ZIP archives spanning multiple files
**    *  No support for zip64 extensions
**    *  Only the "inflate/deflate" (zlib) compression method is supported
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if !defined(_WIN32) && !defined(WIN32)
#  include <unistd.h>
#  include <dirent.h>
#  include <utime.h>
#else
#  include <io.h>
#endif
#include <time.h>
#include <errno.h>

#include <zlib.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE

#ifndef SQLITE_AMALGAMATION
typedef sqlite3_int64 i64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
#define MIN(a,b) ((a)<(b) ? (a) : (b))
#endif

static const char ZIPFILE_SCHEMA[] = 
  "CREATE TABLE y("
    "name PRIMARY KEY,"  /* 0: Name of file in zip archive */
    "mode,"              /* 1: POSIX mode for file */
    "mtime,"             /* 2: Last modification time (secs since 1970)*/
    "sz,"                /* 3: Size of object */
    "rawdata,"           /* 4: Raw data */
    "data,"              /* 5: Uncompressed data */
    "method,"            /* 6: Compression method (integer) */
    "z HIDDEN"           /* 7: Name of zip file */
  ") WITHOUT ROWID;";

#define ZIPFILE_F_COLUMN_IDX 7    /* Index of column "file" in the above */
#define ZIPFILE_BUFFER_SIZE (64*1024)


/*
** Magic numbers used to read and write zip files.
**
** ZIPFILE_NEWENTRY_MADEBY:
**   Use this value for the "version-made-by" field in new zip file
**   entries. The upper byte indicates "unix", and the lower byte 
**   indicates that the zip file matches pkzip specification 3.0. 
**   This is what info-zip seems to do.
**
** ZIPFILE_NEWENTRY_REQUIRED:
**   Value for "version-required-to-extract" field of new entries.
**   Version 2.0 is required to support folders and deflate compression.
**
** ZIPFILE_NEWENTRY_FLAGS:
**   Value for "general-purpose-bit-flags" field of new entries. Bit
**   11 means "utf-8 filename and comment".
**
** ZIPFILE_SIGNATURE_CDS:
**   First 4 bytes of a valid CDS record.
**
** ZIPFILE_SIGNATURE_LFH:
**   First 4 bytes of a valid LFH record.
*/
#define ZIPFILE_EXTRA_TIMESTAMP   0x5455
#define ZIPFILE_NEWENTRY_MADEBY   ((3<<8) + 30)
#define ZIPFILE_NEWENTRY_REQUIRED 20
#define ZIPFILE_NEWENTRY_FLAGS    0x800
#define ZIPFILE_SIGNATURE_CDS     0x02014b50
#define ZIPFILE_SIGNATURE_LFH     0x04034b50
#define ZIPFILE_SIGNATURE_EOCD    0x06054b50
#define ZIPFILE_LFH_FIXED_SZ      30

/*
** Set the error message contained in context ctx to the results of
** vprintf(zFmt, ...).
*/
static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
  char *zMsg = 0;
  va_list ap;
  va_start(ap, zFmt);
  zMsg = sqlite3_vmprintf(zFmt, ap);
  sqlite3_result_error(ctx, zMsg, -1);
  sqlite3_free(zMsg);
  va_end(ap);
}


/*
*** 4.3.16  End of central directory record:
***
***   end of central dir signature    4 bytes  (0x06054b50)
***   number of this disk             2 bytes
***   number of the disk with the
***   start of the central directory  2 bytes
***   total number of entries in the
***   central directory on this disk  2 bytes
***   total number of entries in
***   the central directory           2 bytes
***   size of the central directory   4 bytes
***   offset of start of central
***   directory with respect to
***   the starting disk number        4 bytes
***   .ZIP file comment length        2 bytes
***   .ZIP file comment       (variable size)
*/
typedef struct ZipfileEOCD ZipfileEOCD;
struct ZipfileEOCD {
  u16 iDisk;
  u16 iFirstDisk;
  u16 nEntry;
  u16 nEntryTotal;
  u32 nSize;
  u32 iOffset;
};

/*
*** 4.3.12  Central directory structure:
***
*** ...
***
***   central file header signature   4 bytes  (0x02014b50)
***   version made by                 2 bytes
***   version needed to extract       2 bytes
***   general purpose bit flag        2 bytes
***   compression method              2 bytes
***   last mod file time              2 bytes
***   last mod file date              2 bytes
***   crc-32                          4 bytes
***   compressed size                 4 bytes
***   uncompressed size               4 bytes
***   file name length                2 bytes
***   extra field length              2 bytes
***   file comment length             2 bytes
***   disk number start               2 bytes
***   internal file attributes        2 bytes
***   external file attributes        4 bytes
***   relative offset of local header 4 bytes
*/
typedef struct ZipfileCDS ZipfileCDS;
struct ZipfileCDS {
  u16 iVersionMadeBy;
  u16 iVersionExtract;
  u16 flags;
  u16 iCompression;
  u16 mTime;
  u16 mDate;
  u32 crc32;
  u32 szCompressed;
  u32 szUncompressed;
  u16 nFile;
  u16 nExtra;
  u16 nComment;
  u16 iDiskStart;
  u16 iInternalAttr;
  u32 iExternalAttr;
  u32 iOffset;
  char *zFile;                    /* Filename (sqlite3_malloc()) */
};

/*
*** 4.3.7  Local file header:
***
***   local file header signature     4 bytes  (0x04034b50)
***   version needed to extract       2 bytes
***   general purpose bit flag        2 bytes
***   compression method              2 bytes
***   last mod file time              2 bytes
***   last mod file date              2 bytes
***   crc-32                          4 bytes
***   compressed size                 4 bytes
***   uncompressed size               4 bytes
***   file name length                2 bytes
***   extra field length              2 bytes
***   
*/
typedef struct ZipfileLFH ZipfileLFH;
struct ZipfileLFH {
  u16 iVersionExtract;
  u16 flags;
  u16 iCompression;
  u16 mTime;
  u16 mDate;
  u32 crc32;
  u32 szCompressed;
  u32 szUncompressed;
  u16 nFile;
  u16 nExtra;
};

typedef struct ZipfileEntry ZipfileEntry;
struct ZipfileEntry {
  char *zPath;               /* Path of zipfile entry */
  u8 *aCdsEntry;             /* Buffer containing entire CDS entry */
  int nCdsEntry;             /* Size of buffer aCdsEntry[] in bytes */
  int bDeleted;              /* True if entry has been deleted */
  ZipfileEntry *pNext;       /* Next element in in-memory CDS */
};

/* 
** Cursor type for recursively iterating through a directory structure.
*/
typedef struct ZipfileCsr ZipfileCsr;
struct ZipfileCsr {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  i64 iId;                   /* Cursor ID */
  int bEof;                  /* True when at EOF */

  /* Used outside of write transactions */
  FILE *pFile;               /* Zip file */
  i64 iNextOff;              /* Offset of next record in central directory */
  ZipfileEOCD eocd;          /* Parse of central directory record */

  /* Used inside write transactions */
  ZipfileEntry *pCurrent;

  ZipfileCDS cds;            /* Central Directory Structure */
  ZipfileLFH lfh;            /* Local File Header for current entry */
  i64 iDataOff;              /* Offset in zipfile to data */
  u32 mTime;                 /* Extended mtime value */
  int flags;                 /* Flags byte (see below for bits) */
  ZipfileCsr *pCsrNext;      /* Next cursor on same virtual table */
};

/*
** Values for ZipfileCsr.flags.
*/
#define ZIPFILE_MTIME_VALID 0x0001

typedef struct ZipfileTab ZipfileTab;
struct ZipfileTab {
  sqlite3_vtab base;         /* Base class - must be first */
  char *zFile;               /* Zip file this table accesses (may be NULL) */
  u8 *aBuffer;               /* Temporary buffer used for various tasks */

  ZipfileCsr *pCsrList;      /* List of cursors */
  i64 iNextCsrid;

  /* The following are used by write transactions only */
  ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */
  ZipfileEntry *pLastEntry;  /* Last element in pFirstEntry list */
  FILE *pWriteFd;            /* File handle open on zip archive */
  i64 szCurrent;             /* Current size of zip archive */
  i64 szOrig;                /* Size of archive at start of transaction */
};

static void zipfileDequote(char *zIn){
  char q = zIn[0];
  if( q=='"' || q=='\'' || q=='`' || q=='[' ){
    char c;
    int iIn = 1;
    int iOut = 0;
    if( q=='[' ) q = ']';
    while( (c = zIn[iIn++]) ){
      if( c==q ){
        if( zIn[iIn++]!=q ) break;
      }
      zIn[iOut++] = c;
    }
    zIn[iOut] = '\0';
  }
}

/*
** Construct a new ZipfileTab virtual table object.
** 
**   argv[0]   -> module name  ("zipfile")
**   argv[1]   -> database name
**   argv[2]   -> table name
**   argv[...] -> "column name" and other module argument fields.
*/
static int zipfileConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE;
  int nFile = 0;
  const char *zFile = 0;
  ZipfileTab *pNew = 0;
  int rc;

  if( argc>3 ){
    zFile = argv[3];
    nFile = (int)strlen(zFile)+1;
  }

  rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
  if( rc==SQLITE_OK ){
    pNew = (ZipfileTab*)sqlite3_malloc(nByte+nFile);
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, nByte+nFile);
    pNew->aBuffer = (u8*)&pNew[1];
    if( zFile ){
      pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE];
      memcpy(pNew->zFile, zFile, nFile);
      zipfileDequote(pNew->zFile);
    }
  }
  *ppVtab = (sqlite3_vtab*)pNew;
  return rc;
}

/*
** This method is the destructor for zipfile vtab objects.
*/
static int zipfileDisconnect(sqlite3_vtab *pVtab){
  sqlite3_free(pVtab);
  return SQLITE_OK;
}

/*
** Constructor for a new ZipfileCsr object.
*/
static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
  ZipfileTab *pTab = (ZipfileTab*)p;
  ZipfileCsr *pCsr;
  pCsr = sqlite3_malloc(sizeof(*pCsr));
  *ppCsr = (sqlite3_vtab_cursor*)pCsr;
  if( pCsr==0 ){
    return SQLITE_NOMEM;
  }
  memset(pCsr, 0, sizeof(*pCsr));
  pCsr->iId = ++pTab->iNextCsrid;
  pCsr->pCsrNext = pTab->pCsrList;
  pTab->pCsrList = pCsr;
  return SQLITE_OK;
}

/*
** Reset a cursor back to the state it was in when first returned
** by zipfileOpen().
*/
static void zipfileResetCursor(ZipfileCsr *pCsr){
  sqlite3_free(pCsr->cds.zFile);
  pCsr->cds.zFile = 0;
  pCsr->bEof = 0;
  if( pCsr->pFile ){
    fclose(pCsr->pFile);
    pCsr->pFile = 0;
  }
}

/*
** Destructor for an ZipfileCsr.
*/
static int zipfileClose(sqlite3_vtab_cursor *cur){
  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab);
  ZipfileCsr **pp;
  zipfileResetCursor(pCsr);

  /* Remove this cursor from the ZipfileTab.pCsrList list. */
  for(pp=&pTab->pCsrList; *pp; pp=&((*pp)->pCsrNext)){
    if( *pp==pCsr ){ 
      *pp = pCsr->pCsrNext;
      break;
    }
  }

  sqlite3_free(pCsr);
  return SQLITE_OK;
}

/*
** Set the error message for the virtual table associated with cursor
** pCsr to the results of vprintf(zFmt, ...).
*/
static void zipfileSetErrmsg(ZipfileCsr *pCsr, const char *zFmt, ...){
  va_list ap;
  va_start(ap, zFmt);
  pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
  va_end(ap);
}

static int zipfileReadData(
  FILE *pFile,                    /* Read from this file */
  u8 *aRead,                      /* Read into this buffer */
  int nRead,                      /* Number of bytes to read */
  i64 iOff,                       /* Offset to read from */
  char **pzErrmsg                 /* OUT: Error message (from sqlite3_malloc) */
){
  size_t n;
  fseek(pFile, (long)iOff, SEEK_SET);
  n = fread(aRead, 1, nRead, pFile);
  if( (int)n!=nRead ){
    *pzErrmsg = sqlite3_mprintf("error in fread()");
    return SQLITE_ERROR;
  }
  return SQLITE_OK;
}

static int zipfileAppendData(
  ZipfileTab *pTab,
  const u8 *aWrite,
  int nWrite
){
  size_t n;
  fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
  n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
  if( (int)n!=nWrite ){
    pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
    return SQLITE_ERROR;
  }
  pTab->szCurrent += nWrite;
  return SQLITE_OK;
}

static u16 zipfileGetU16(const u8 *aBuf){
  return (aBuf[1] << 8) + aBuf[0];
}
static u32 zipfileGetU32(const u8 *aBuf){
  return ((u32)(aBuf[3]) << 24)
       + ((u32)(aBuf[2]) << 16)
       + ((u32)(aBuf[1]) <<  8)
       + ((u32)(aBuf[0]) <<  0);
}

static void zipfilePutU16(u8 *aBuf, u16 val){
  aBuf[0] = val & 0xFF;
  aBuf[1] = (val>>8) & 0xFF;
}
static void zipfilePutU32(u8 *aBuf, u32 val){
  aBuf[0] = val & 0xFF;
  aBuf[1] = (val>>8) & 0xFF;
  aBuf[2] = (val>>16) & 0xFF;
  aBuf[3] = (val>>24) & 0xFF;
}

#define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) )
#define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) )

#define zipfileWrite32(aBuf,val) { zipfilePutU32(aBuf,val); aBuf+=4; }
#define zipfileWrite16(aBuf,val) { zipfilePutU16(aBuf,val); aBuf+=2; }

static u8* zipfileCsrBuffer(ZipfileCsr *pCsr){
  return ((ZipfileTab*)(pCsr->base.pVtab))->aBuffer;
}

/*
** Magic numbers used to read CDS records.
*/
#define ZIPFILE_CDS_FIXED_SZ         46
#define ZIPFILE_CDS_NFILE_OFF        28

/*
** Decode the CDS record in buffer aBuf into (*pCDS). Return SQLITE_ERROR
** if the record is not well-formed, or SQLITE_OK otherwise.
*/
static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){
  u8 *aRead = aBuf;
  u32 sig = zipfileRead32(aRead);
  int rc = SQLITE_OK;
  if( sig!=ZIPFILE_SIGNATURE_CDS ){
    rc = SQLITE_ERROR;
  }else{
    pCDS->iVersionMadeBy = zipfileRead16(aRead);
    pCDS->iVersionExtract = zipfileRead16(aRead);
    pCDS->flags = zipfileRead16(aRead);
    pCDS->iCompression = zipfileRead16(aRead);
    pCDS->mTime = zipfileRead16(aRead);
    pCDS->mDate = zipfileRead16(aRead);
    pCDS->crc32 = zipfileRead32(aRead);
    pCDS->szCompressed = zipfileRead32(aRead);
    pCDS->szUncompressed = zipfileRead32(aRead);
    assert( aRead==&aBuf[ZIPFILE_CDS_NFILE_OFF] );
    pCDS->nFile = zipfileRead16(aRead);
    pCDS->nExtra = zipfileRead16(aRead);
    pCDS->nComment = zipfileRead16(aRead);
    pCDS->iDiskStart = zipfileRead16(aRead);
    pCDS->iInternalAttr = zipfileRead16(aRead);
    pCDS->iExternalAttr = zipfileRead32(aRead);
    pCDS->iOffset = zipfileRead32(aRead);
    assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] );
  }

  return rc;
}

/*
** Read the CDS record for the current entry from disk into pCsr->cds.
*/
static int zipfileCsrReadCDS(ZipfileCsr *pCsr){
  char **pzErr = &pCsr->base.pVtab->zErrMsg;
  u8 *aRead;
  int rc = SQLITE_OK;

  sqlite3_free(pCsr->cds.zFile);
  pCsr->cds.zFile = 0;

  if( pCsr->pCurrent==0 ){
    aRead = zipfileCsrBuffer(pCsr);
    rc = zipfileReadData(
        pCsr->pFile, aRead, ZIPFILE_CDS_FIXED_SZ, pCsr->iNextOff, pzErr
    );
  }else{
    aRead = pCsr->pCurrent->aCdsEntry;
  }

  if( rc==SQLITE_OK ){
    rc = zipfileReadCDS(aRead, &pCsr->cds);
    if( rc!=SQLITE_OK ){
      assert( pCsr->pCurrent==0 );
      zipfileSetErrmsg(pCsr,"failed to read CDS at offset %lld",pCsr->iNextOff);
    }else{
      int nRead;
      if( pCsr->pCurrent==0 ){
        nRead = pCsr->cds.nFile + pCsr->cds.nExtra;
        aRead = zipfileCsrBuffer(pCsr);
        pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ;
        rc = zipfileReadData(pCsr->pFile, aRead, nRead, pCsr->iNextOff, pzErr);
      }else{
        aRead = &aRead[ZIPFILE_CDS_FIXED_SZ];
      }

      if( rc==SQLITE_OK ){
        pCsr->cds.zFile = sqlite3_mprintf("%.*s", (int)pCsr->cds.nFile, aRead);
        pCsr->iNextOff += pCsr->cds.nFile;
        pCsr->iNextOff += pCsr->cds.nExtra;
        pCsr->iNextOff += pCsr->cds.nComment;
      }

      /* Scan the cds.nExtra bytes of "extra" fields for any that can
      ** be interpreted. The general format of an extra field is:
      **
      **   Header ID    2 bytes
      **   Data Size    2 bytes
      **   Data         N bytes
      **
      */
      if( rc==SQLITE_OK ){
        u8 *p = &aRead[pCsr->cds.nFile];
        u8 *pEnd = &p[pCsr->cds.nExtra];

        while( p<pEnd ){
          u16 id = zipfileRead16(p);
          u16 nByte = zipfileRead16(p);

          switch( id ){
            case ZIPFILE_EXTRA_TIMESTAMP: {
              u8 b = p[0];
              if( b & 0x01 ){     /* 0x01 -> modtime is present */
                pCsr->mTime = zipfileGetU32(&p[1]);
                pCsr->flags |= ZIPFILE_MTIME_VALID;
              }
              break;
            }
          }

          p += nByte;
        }
      }
    }
  }

  return rc;
}

static FILE *zipfileGetFd(ZipfileCsr *pCsr){
  if( pCsr->pFile ) return pCsr->pFile;
  return ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd;
}

static int zipfileReadLFH(
  FILE *pFd, 
  i64 iOffset,
  u8 *aTmp, 
  ZipfileLFH *pLFH, 
  char **pzErr
){
  u8 *aRead = aTmp;
  static const int szFix = ZIPFILE_LFH_FIXED_SZ;
  int rc;

  rc = zipfileReadData(pFd, aRead, szFix, iOffset, pzErr);
  if( rc==SQLITE_OK ){
    u32 sig = zipfileRead32(aRead);
    if( sig!=ZIPFILE_SIGNATURE_LFH ){
      *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", (int)iOffset);
      rc = SQLITE_ERROR;
    }else{
      pLFH->iVersionExtract = zipfileRead16(aRead);
      pLFH->flags = zipfileRead16(aRead);
      pLFH->iCompression = zipfileRead16(aRead);
      pLFH->mTime = zipfileRead16(aRead);
      pLFH->mDate = zipfileRead16(aRead);
      pLFH->crc32 = zipfileRead32(aRead);
      pLFH->szCompressed = zipfileRead32(aRead);
      pLFH->szUncompressed = zipfileRead32(aRead);
      pLFH->nFile = zipfileRead16(aRead);
      pLFH->nExtra = zipfileRead16(aRead);
      assert( aRead==&aTmp[szFix] );
    }
  }
  return rc;
}

static int zipfileCsrReadLFH(ZipfileCsr *pCsr){
  FILE *pFile = zipfileGetFd(pCsr);
  char **pzErr = &pCsr->base.pVtab->zErrMsg;
  u8 *aRead = zipfileCsrBuffer(pCsr);
  int rc = zipfileReadLFH(pFile, pCsr->cds.iOffset, aRead, &pCsr->lfh, pzErr);
  pCsr->iDataOff =  pCsr->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
  pCsr->iDataOff += pCsr->lfh.nFile+pCsr->lfh.nExtra;
  return rc;
}


/*
** Advance an ZipfileCsr to its next row of output.
*/
static int zipfileNext(sqlite3_vtab_cursor *cur){
  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  int rc = SQLITE_OK;
  pCsr->flags = 0;

  if( pCsr->pCurrent==0 ){
    i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize;
    if( pCsr->iNextOff>=iEof ){
      pCsr->bEof = 1;
    }
  }else{
    assert( pCsr->pFile==0 );
    do {
      pCsr->pCurrent = pCsr->pCurrent->pNext;
    }while( pCsr->pCurrent && pCsr->pCurrent->bDeleted );
    if( pCsr->pCurrent==0 ){
      pCsr->bEof = 1;
    }
  }

  if( pCsr->bEof==0 ){
    rc = zipfileCsrReadCDS(pCsr);
    if( rc==SQLITE_OK ){
      rc = zipfileCsrReadLFH(pCsr);
    }
  }

  return rc;
}

/*
** "Standard" MS-DOS time format:
**
**   File modification time:
**     Bits 00-04: seconds divided by 2
**     Bits 05-10: minute
**     Bits 11-15: hour
**   File modification date:
**     Bits 00-04: day
**     Bits 05-08: month (1-12)
**     Bits 09-15: years from 1980 
*/
static time_t zipfileMtime(ZipfileCsr *pCsr){
  struct tm t;
  memset(&t, 0, sizeof(t));
  t.tm_sec = (pCsr->cds.mTime & 0x1F)*2;
  t.tm_min = (pCsr->cds.mTime >> 5) & 0x2F;
  t.tm_hour = (pCsr->cds.mTime >> 11) & 0x1F;

  t.tm_mday = (pCsr->cds.mDate & 0x1F);
  t.tm_mon = ((pCsr->cds.mDate >> 5) & 0x0F) - 1;
  t.tm_year = 80 + ((pCsr->cds.mDate >> 9) & 0x7F);

  return mktime(&t);
}

static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mTime){
  time_t t = (time_t)mTime;
  struct tm res;

#if !defined(_WIN32) && !defined(WIN32)
  localtime_r(&t, &res);
#else
  memcpy(&res, localtime(&t), sizeof(struct tm));
#endif

  pCds->mTime = (u16)(
    (res.tm_sec / 2) + 
    (res.tm_min << 5) +
    (res.tm_hour << 11));

  pCds->mDate = (u16)(
    (res.tm_mday-1) +
    ((res.tm_mon+1) << 5) +
    ((res.tm_year-80) << 9));
}

static void zipfileInflate(
  sqlite3_context *pCtx,          /* Store error here, if any */
  const u8 *aIn,                  /* Compressed data */
  int nIn,                        /* Size of buffer aIn[] in bytes */
  int nOut                        /* Expected output size */
){
  u8 *aRes = sqlite3_malloc(nOut);
  if( aRes==0 ){
    sqlite3_result_error_nomem(pCtx);
  }else{
    int err;
    z_stream str;
    memset(&str, 0, sizeof(str));

    str.next_in = (Byte*)aIn;
    str.avail_in = nIn;
    str.next_out = (Byte*)aRes;
    str.avail_out = nOut;

    err = inflateInit2(&str, -15);
    if( err!=Z_OK ){
      zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err);
    }else{
      err = inflate(&str, Z_NO_FLUSH);
      if( err!=Z_STREAM_END ){
        zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err);
      }else{
        sqlite3_result_blob(pCtx, aRes, nOut, SQLITE_TRANSIENT);
      }
    }
    sqlite3_free(aRes);
    inflateEnd(&str);
  }
}

static int zipfileDeflate(
  ZipfileTab *pTab,               /* Set error message here */
  const u8 *aIn, int nIn,         /* Input */
  u8 **ppOut, int *pnOut          /* Output */
){
  int nAlloc = (int)compressBound(nIn);
  u8 *aOut;
  int rc = SQLITE_OK;

  aOut = (u8*)sqlite3_malloc(nAlloc);
  if( aOut==0 ){
    rc = SQLITE_NOMEM;
  }else{
    int res;
    z_stream str;
    memset(&str, 0, sizeof(str));
    str.next_in = (Bytef*)aIn;
    str.avail_in = nIn;
    str.next_out = aOut;
    str.avail_out = nAlloc;

    deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
    res = deflate(&str, Z_FINISH);

    if( res==Z_STREAM_END ){
      *ppOut = aOut;
      *pnOut = (int)str.total_out;
    }else{
      sqlite3_free(aOut);
      pTab->base.zErrMsg = sqlite3_mprintf("zipfile: deflate() error");
      rc = SQLITE_ERROR;
    }
    deflateEnd(&str);
  }

  return rc;
}


/*
** Return values of columns for the row at which the series_cursor
** is currently pointing.
*/
static int zipfileColumn(
  sqlite3_vtab_cursor *cur,   /* The cursor */
  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
  int i                       /* Which column to return */
){
  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  int rc = SQLITE_OK;
  switch( i ){
    case 0:   /* name */
      sqlite3_result_text(ctx, pCsr->cds.zFile, -1, SQLITE_TRANSIENT);
      break;
    case 1:   /* mode */
      /* TODO: Whether or not the following is correct surely depends on
      ** the platform on which the archive was created.  */
      sqlite3_result_int(ctx, pCsr->cds.iExternalAttr >> 16);
      break;
    case 2: { /* mtime */
      if( pCsr->flags & ZIPFILE_MTIME_VALID ){
        sqlite3_result_int64(ctx, pCsr->mTime);
      }else{
        sqlite3_result_int64(ctx, zipfileMtime(pCsr));
      }
      break;
    }
    case 3: { /* sz */
      if( sqlite3_vtab_nochange(ctx)==0 ){
        sqlite3_result_int64(ctx, pCsr->cds.szUncompressed);
      }
      break;
    }
    case 4:   /* rawdata */
      if( sqlite3_vtab_nochange(ctx) ) break;
    case 5: { /* data */
      if( i==4 || pCsr->cds.iCompression==0 || pCsr->cds.iCompression==8 ){
        int sz = pCsr->cds.szCompressed;
        int szFinal = pCsr->cds.szUncompressed;
        if( szFinal>0 ){
          u8 *aBuf = sqlite3_malloc(sz);
          if( aBuf==0 ){
            rc = SQLITE_NOMEM;
          }else{
            FILE *pFile = zipfileGetFd(pCsr);
            rc = zipfileReadData(pFile, aBuf, sz, pCsr->iDataOff,
                &pCsr->base.pVtab->zErrMsg
            );
          }
          if( rc==SQLITE_OK ){
            if( i==5 && pCsr->cds.iCompression ){
              zipfileInflate(ctx, aBuf, sz, szFinal);
            }else{
              sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT);
            }
            sqlite3_free(aBuf);
          }
        }else{
          /* Figure out if this is a directory or a zero-sized file. Consider
          ** it to be a directory either if the mode suggests so, or if
          ** the final character in the name is '/'.  */
          u32 mode = pCsr->cds.iExternalAttr >> 16;
          if( !(mode & S_IFDIR) && pCsr->cds.zFile[pCsr->cds.nFile-1]!='/' ){
            sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
          }
        }
      }
      break;
    }
    case 6:   /* method */
      sqlite3_result_int(ctx, pCsr->cds.iCompression);
      break;
    case 7:   /* z */
      sqlite3_result_int64(ctx, pCsr->iId);
      break;
  }

  return rc;
}

/*
** Return the rowid for the current row.
*/
static int zipfileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  assert( 0 );
  return SQLITE_OK;
}

/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int zipfileEof(sqlite3_vtab_cursor *cur){
  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  return pCsr->bEof;
}

/*
*/
static int zipfileReadEOCD(
  ZipfileTab *pTab,               /* Return errors here */
  FILE *pFile,                    /* Read from this file */
  ZipfileEOCD *pEOCD              /* Object to populate */
){
  u8 *aRead = pTab->aBuffer;      /* Temporary buffer */
  i64 szFile;                     /* Total size of file in bytes */
  int nRead;                      /* Bytes to read from file */
  i64 iOff;                       /* Offset to read from */
  int rc;

  fseek(pFile, 0, SEEK_END);
  szFile = (i64)ftell(pFile);
  if( szFile==0 ){
    memset(pEOCD, 0, sizeof(ZipfileEOCD));
    return SQLITE_OK;
  }
  nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
  iOff = szFile - nRead;

  rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
  if( rc==SQLITE_OK ){
    int i;

    /* Scan backwards looking for the signature bytes */
    for(i=nRead-20; i>=0; i--){
      if( aRead[i]==0x50 && aRead[i+1]==0x4b 
       && aRead[i+2]==0x05 && aRead[i+3]==0x06 
      ){
        break;
      }
    }
    if( i<0 ){
      pTab->base.zErrMsg = sqlite3_mprintf(
          "cannot find end of central directory record"
      );
      return SQLITE_ERROR;
    }

    aRead += i+4;
    pEOCD->iDisk = zipfileRead16(aRead);
    pEOCD->iFirstDisk = zipfileRead16(aRead);
    pEOCD->nEntry = zipfileRead16(aRead);
    pEOCD->nEntryTotal = zipfileRead16(aRead);
    pEOCD->nSize = zipfileRead32(aRead);
    pEOCD->iOffset = zipfileRead32(aRead);

#if 0
    printf("iDisk=%d  iFirstDisk=%d  nEntry=%d  "
           "nEntryTotal=%d  nSize=%d  iOffset=%d", 
           (int)pEOCD->iDisk, (int)pEOCD->iFirstDisk, (int)pEOCD->nEntry,
           (int)pEOCD->nEntryTotal, (int)pEOCD->nSize, (int)pEOCD->iOffset
    );
#endif
  }

  return SQLITE_OK;
}

/*
** xFilter callback.
*/
static int zipfileFilter(
  sqlite3_vtab_cursor *cur, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  ZipfileTab *pTab = (ZipfileTab*)cur->pVtab;
  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
  const char *zFile;              /* Zip file to scan */
  int rc = SQLITE_OK;             /* Return Code */

  zipfileResetCursor(pCsr);

  if( pTab->zFile ){
    zFile = pTab->zFile;
  }else if( idxNum==0 ){
    /* Error. This is an eponymous virtual table and the user has not 
    ** supplied a file name. */
    zipfileSetErrmsg(pCsr, "table function zipfile() requires an argument");
    return SQLITE_ERROR;
  }else{
    zFile = (const char*)sqlite3_value_text(argv[0]);
  }

  if( pTab->pWriteFd==0 ){
    pCsr->pFile = fopen(zFile, "rb");
    if( pCsr->pFile==0 ){
      zipfileSetErrmsg(pCsr, "cannot open file: %s", zFile);
      rc = SQLITE_ERROR;
    }else{
      rc = zipfileReadEOCD(pTab, pCsr->pFile, &pCsr->eocd);
      if( rc==SQLITE_OK ){
        if( pCsr->eocd.nEntry==0 ){
          pCsr->bEof = 1;
        }else{
          pCsr->iNextOff = pCsr->eocd.iOffset;
          rc = zipfileNext(cur);
        }
      }
    }
  }else{
    ZipfileEntry e;
    memset(&e, 0, sizeof(e));
    e.pNext = pTab->pFirstEntry;
    pCsr->pCurrent = &e;
    rc = zipfileNext(cur);
    assert( pCsr->pCurrent!=&e );
  }

  return rc;
}

/*
** xBestIndex callback.
*/
static int zipfileBestIndex(
  sqlite3_vtab *tab,
  sqlite3_index_info *pIdxInfo
){
  int i;

  for(i=0; i<pIdxInfo->nConstraint; i++){
    const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
    if( pCons->usable==0 ) continue;
    if( pCons->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
    break;
  }

  if( i<pIdxInfo->nConstraint ){
    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
    pIdxInfo->aConstraintUsage[i].omit = 1;
    pIdxInfo->estimatedCost = 1000.0;
    pIdxInfo->idxNum = 1;
  }else{
    pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
    pIdxInfo->idxNum = 0;
  }

  return SQLITE_OK;
}

/*
** Add object pNew to the end of the linked list that begins at
** ZipfileTab.pFirstEntry and ends with pLastEntry.
*/
static void zipfileAddEntry(
  ZipfileTab *pTab, 
  ZipfileEntry *pBefore, 
  ZipfileEntry *pNew
){
  assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
  assert( pNew->pNext==0 );
  if( pBefore==0 ){
    if( pTab->pFirstEntry==0 ){
      pTab->pFirstEntry = pTab->pLastEntry = pNew;
    }else{
      assert( pTab->pLastEntry->pNext==0 );
      pTab->pLastEntry->pNext = pNew;
      pTab->pLastEntry = pNew;
    }
  }else{
    ZipfileEntry **pp;
    for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext));
    pNew->pNext = pBefore;
    *pp = pNew;
  }
}

static int zipfileLoadDirectory(ZipfileTab *pTab){
  ZipfileEOCD eocd;
  int rc;

  rc = zipfileReadEOCD(pTab, pTab->pWriteFd, &eocd);
  if( rc==SQLITE_OK && eocd.nEntry>0 ){
    int i;
    int iOff = 0;
    u8 *aBuf = sqlite3_malloc(eocd.nSize);
    if( aBuf==0 ){
      rc = SQLITE_NOMEM;
    }else{
      rc = zipfileReadData(
          pTab->pWriteFd, aBuf, eocd.nSize, eocd.iOffset, &pTab->base.zErrMsg
      );
    }

    for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){
      u16 nFile;
      u16 nExtra;
      u16 nComment;
      ZipfileEntry *pNew;
      u8 *aRec = &aBuf[iOff];

      nFile = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF]);
      nExtra = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF+2]);
      nComment = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF+4]);

      pNew = sqlite3_malloc(
          sizeof(ZipfileEntry) 
        + nFile+1 
        + ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment
      );
      if( pNew==0 ){
        rc = SQLITE_NOMEM;
      }else{
        memset(pNew, 0, sizeof(ZipfileEntry));
        pNew->zPath = (char*)&pNew[1];
        memcpy(pNew->zPath, &aRec[ZIPFILE_CDS_FIXED_SZ], nFile);
        pNew->zPath[nFile] = '\0';
        pNew->aCdsEntry = (u8*)&pNew->zPath[nFile+1];
        pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
        memcpy(pNew->aCdsEntry, aRec, pNew->nCdsEntry);
        zipfileAddEntry(pTab, 0, pNew);
      }

      iOff += ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
    }

    sqlite3_free(aBuf);
  }

  return rc;
}

static ZipfileEntry *zipfileNewEntry(
  ZipfileCDS *pCds,               /* Values for fixed size part of CDS */
  const char *zPath,              /* Path for new entry */
  int nPath,                      /* strlen(zPath) */
  u32 mTime                       /* Modification time (or 0) */
){
  u8 *aWrite;
  ZipfileEntry *pNew;
  pCds->nFile = (u16)nPath;
  pCds->nExtra = mTime ? 9 : 0;
  pNew = (ZipfileEntry*)sqlite3_malloc(
    sizeof(ZipfileEntry) + 
    nPath+1 + 
    ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra
  );

  if( pNew ){
    memset(pNew, 0, sizeof(ZipfileEntry));
    pNew->zPath = (char*)&pNew[1];
    pNew->aCdsEntry = (u8*)&pNew->zPath[nPath+1];
    pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra;
    memcpy(pNew->zPath, zPath, nPath+1);

    aWrite = pNew->aCdsEntry;
    zipfileWrite32(aWrite, ZIPFILE_SIGNATURE_CDS);
    zipfileWrite16(aWrite, pCds->iVersionMadeBy);
    zipfileWrite16(aWrite, pCds->iVersionExtract);
    zipfileWrite16(aWrite, pCds->flags);
    zipfileWrite16(aWrite, pCds->iCompression);
    zipfileWrite16(aWrite, pCds->mTime);
    zipfileWrite16(aWrite, pCds->mDate);
    zipfileWrite32(aWrite, pCds->crc32);
    zipfileWrite32(aWrite, pCds->szCompressed);
    zipfileWrite32(aWrite, pCds->szUncompressed);
    zipfileWrite16(aWrite, pCds->nFile);
    zipfileWrite16(aWrite, pCds->nExtra);
    zipfileWrite16(aWrite, pCds->nComment);      assert( pCds->nComment==0 );
    zipfileWrite16(aWrite, pCds->iDiskStart);
    zipfileWrite16(aWrite, pCds->iInternalAttr);
    zipfileWrite32(aWrite, pCds->iExternalAttr);
    zipfileWrite32(aWrite, pCds->iOffset);
    assert( aWrite==&pNew->aCdsEntry[ZIPFILE_CDS_FIXED_SZ] );
    memcpy(aWrite, zPath, nPath);
    if( pCds->nExtra ){
      aWrite += nPath;
      zipfileWrite16(aWrite, ZIPFILE_EXTRA_TIMESTAMP);
      zipfileWrite16(aWrite, 5);
      *aWrite++ = 0x01;
      zipfileWrite32(aWrite, mTime);
    }
  }

  return pNew;
}

static int zipfileAppendEntry(
  ZipfileTab *pTab,
  ZipfileCDS *pCds,
  const char *zPath,              /* Path for new entry */
  int nPath,                      /* strlen(zPath) */
  const u8 *pData,
  int nData,
  u32 mTime
){
  u8 *aBuf = pTab->aBuffer;
  int rc;

  zipfileWrite32(aBuf, ZIPFILE_SIGNATURE_LFH);
  zipfileWrite16(aBuf, pCds->iVersionExtract);
  zipfileWrite16(aBuf, pCds->flags);
  zipfileWrite16(aBuf, pCds->iCompression);
  zipfileWrite16(aBuf, pCds->mTime);
  zipfileWrite16(aBuf, pCds->mDate);
  zipfileWrite32(aBuf, pCds->crc32);
  zipfileWrite32(aBuf, pCds->szCompressed);
  zipfileWrite32(aBuf, pCds->szUncompressed);
  zipfileWrite16(aBuf, (u16)nPath);
  zipfileWrite16(aBuf, pCds->nExtra);
  assert( aBuf==&pTab->aBuffer[ZIPFILE_LFH_FIXED_SZ] );
  rc = zipfileAppendData(pTab, pTab->aBuffer, (int)(aBuf - pTab->aBuffer));
  if( rc==SQLITE_OK ){
    rc = zipfileAppendData(pTab, (const u8*)zPath, nPath);
  }

  if( rc==SQLITE_OK && pCds->nExtra ){
    aBuf = pTab->aBuffer;
    zipfileWrite16(aBuf, ZIPFILE_EXTRA_TIMESTAMP);
    zipfileWrite16(aBuf, 5);
    *aBuf++ = 0x01;
    zipfileWrite32(aBuf, mTime);
    rc = zipfileAppendData(pTab, pTab->aBuffer, 9);
  }

  if( rc==SQLITE_OK ){
    rc = zipfileAppendData(pTab, pData, nData);
  }

  return rc;
}

static int zipfileGetMode(
  ZipfileTab *pTab, 
  sqlite3_value *pVal, 
  u32 defaultMode,                /* Value to use if pVal IS NULL */
  u32 *pMode
){
  const char *z = (const char*)sqlite3_value_text(pVal);
  u32 mode = 0;
  if( z==0 ){
    mode = defaultMode;
  }else if( z[0]>='0' && z[0]<='9' ){
    mode = (unsigned int)sqlite3_value_int(pVal);
  }else{
    const char zTemplate[11] = "-rwxrwxrwx";
    int i;
    if( strlen(z)!=10 ) goto parse_error;
    switch( z[0] ){
      case '-': mode |= S_IFREG; break;
      case 'd': mode |= S_IFDIR; break;
#if !defined(_WIN32) && !defined(WIN32)
      case 'l': mode |= S_IFLNK; break;
#endif
      default: goto parse_error;
    }
    for(i=1; i<10; i++){
      if( z[i]==zTemplate[i] ) mode |= 1 << (9-i);
      else if( z[i]!='-' ) goto parse_error;
    }
  }
  *pMode = mode;
  return SQLITE_OK;

 parse_error:
  pTab->base.zErrMsg = sqlite3_mprintf("zipfile: parse error in mode: %s", z);
  return SQLITE_ERROR;
}

/*
** Both (const char*) arguments point to nul-terminated strings. Argument
** nB is the value of strlen(zB). This function returns 0 if the strings are
** identical, ignoring any trailing '/' character in either path.  */
static int zipfileComparePath(const char *zA, const char *zB, int nB){
  int nA = (int)strlen(zA);
  if( zA[nA-1]=='/' ) nA--;
  if( zB[nB-1]=='/' ) nB--;
  if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
  return 1;
}

/*
** xUpdate method.
*/
static int zipfileUpdate(
  sqlite3_vtab *pVtab, 
  int nVal, 
  sqlite3_value **apVal, 
  sqlite_int64 *pRowid
){
  ZipfileTab *pTab = (ZipfileTab*)pVtab;
  int rc = SQLITE_OK;             /* Return Code */
  ZipfileEntry *pNew = 0;         /* New in-memory CDS entry */

  u32 mode = 0;                   /* Mode for new entry */
  i64 mTime = 0;                  /* Modification time for new entry */
  i64 sz = 0;                     /* Uncompressed size */
  const char *zPath = 0;          /* Path for new entry */
  int nPath = 0;                  /* strlen(zPath) */
  const u8 *pData = 0;            /* Pointer to buffer containing content */
  int nData = 0;                  /* Size of pData buffer in bytes */
  int iMethod = 0;                /* Compression method for new entry */
  u8 *pFree = 0;                  /* Free this */
  char *zFree = 0;                /* Also free this */
  ZipfileCDS cds;                 /* New Central Directory Structure entry */
  ZipfileEntry *pOld = 0;
  int bIsDir = 0;
  u32 iCrc32 = 0;

  assert( pTab->zFile );
  assert( pTab->pWriteFd );

  if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
    const char *zDelete = (const char*)sqlite3_value_text(apVal[0]);
    int nDelete = (int)strlen(zDelete);
    for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){
      if( pOld->bDeleted ) continue;
      if( zipfileComparePath(pOld->zPath, zDelete, nDelete)==0 ){
        pOld->bDeleted = 1;
        break;
      }
      assert( pOld->pNext );
    }
    if( nVal==1 ) return SQLITE_OK;
  }

  /* Check that "sz" and "rawdata" are both NULL: */
  if( sqlite3_value_type(apVal[5])!=SQLITE_NULL
   || sqlite3_value_type(apVal[6])!=SQLITE_NULL
  ){
    rc = SQLITE_CONSTRAINT;
  }

  if( rc==SQLITE_OK ){
    if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){
      /* data=NULL. A directory */
      bIsDir = 1;
    }else{
      /* Value specified for "data", and possibly "method". This must be
      ** a regular file or a symlink. */
      const u8 *aIn = sqlite3_value_blob(apVal[7]);
      int nIn = sqlite3_value_bytes(apVal[7]);
      int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;

      iMethod = sqlite3_value_int(apVal[8]);
      sz = nIn;
      pData = aIn;
      nData = nIn;
      if( iMethod!=0 && iMethod!=8 ){
        rc = SQLITE_CONSTRAINT;
      }else{
        if( bAuto || iMethod ){
          int nCmp;
          rc = zipfileDeflate(pTab, aIn, nIn, &pFree, &nCmp);
          if( rc==SQLITE_OK ){
            if( iMethod || nCmp<nIn ){
              iMethod = 8;
              pData = pFree;
              nData = nCmp;
            }
          }
        }
        iCrc32 = crc32(0, aIn, nIn);
      }
    }
  }

  if( rc==SQLITE_OK ){
    rc = zipfileGetMode(pTab, apVal[3], 
        (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644)), &mode
    );
    if( rc==SQLITE_OK && (bIsDir == ((mode & S_IFDIR)==0)) ){
      /* The "mode" attribute is a directory, but data has been specified.
      ** Or vice-versa - no data but "mode" is a file or symlink.  */
      rc = SQLITE_CONSTRAINT;
    }
  }

  if( rc==SQLITE_OK ){
    zPath = (const char*)sqlite3_value_text(apVal[2]);
    nPath = (int)strlen(zPath);
    if( sqlite3_value_type(apVal[4])==SQLITE_NULL ){
      mTime = (sqlite3_int64)time(0);
    }else{
      mTime = sqlite3_value_int64(apVal[4]);
    }
  }

  if( rc==SQLITE_OK && bIsDir ){
    /* For a directory, check that the last character in the path is a
    ** '/'. This appears to be required for compatibility with info-zip
    ** (the unzip command on unix). It does not create directories
    ** otherwise.  */
    if( zPath[nPath-1]!='/' ){
      zFree = sqlite3_mprintf("%s/", zPath);
      if( zFree==0 ){ rc = SQLITE_NOMEM; }
      zPath = (const char*)zFree;
      nPath++;
    }
  }

  /* Check that we're not inserting a duplicate entry */
  if( rc==SQLITE_OK ){
    ZipfileEntry *p;
    for(p=pTab->pFirstEntry; p; p=p->pNext){
      if( p->bDeleted ) continue;
      if( zipfileComparePath(p->zPath, zPath, nPath)==0 ){
        rc = SQLITE_CONSTRAINT;
        break;
      }
    }
  }

  if( rc==SQLITE_OK ){
    /* Create the new CDS record. */
    memset(&cds, 0, sizeof(cds));
    cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
    cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
    cds.flags = ZIPFILE_NEWENTRY_FLAGS;
    cds.iCompression = (u16)iMethod;
    zipfileMtimeToDos(&cds, (u32)mTime);
    cds.crc32 = iCrc32;
    cds.szCompressed = nData;
    cds.szUncompressed = (u32)sz;
    cds.iExternalAttr = (mode<<16);
    cds.iOffset = (u32)pTab->szCurrent;
    pNew = zipfileNewEntry(&cds, zPath, nPath, (u32)mTime);
    if( pNew==0 ){
      rc = SQLITE_NOMEM;
    }else{
      zipfileAddEntry(pTab, pOld, pNew);
    }
  }

  /* Append the new header+file to the archive */
  if( rc==SQLITE_OK ){
    rc = zipfileAppendEntry(pTab, &cds, zPath, nPath, pData, nData, (u32)mTime);
  }

  if( rc!=SQLITE_OK && pOld ){
    pOld->bDeleted = 0;
  }
  sqlite3_free(pFree);
  sqlite3_free(zFree);
  return rc;
}

static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){
  u8 *aBuf = pTab->aBuffer;

  zipfileWrite32(aBuf, ZIPFILE_SIGNATURE_EOCD);
  zipfileWrite16(aBuf, p->iDisk);
  zipfileWrite16(aBuf, p->iFirstDisk);
  zipfileWrite16(aBuf, p->nEntry);
  zipfileWrite16(aBuf, p->nEntryTotal);
  zipfileWrite32(aBuf, p->nSize);
  zipfileWrite32(aBuf, p->iOffset);
  zipfileWrite16(aBuf, 0);        /* Size of trailing comment in bytes*/

  assert( (aBuf-pTab->aBuffer)==22 );
  return zipfileAppendData(pTab, pTab->aBuffer, (int)(aBuf - pTab->aBuffer));
}

static void zipfileCleanupTransaction(ZipfileTab *pTab){
  ZipfileEntry *pEntry;
  ZipfileEntry *pNext;

  for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){
    pNext = pEntry->pNext;
    sqlite3_free(pEntry);
  }
  pTab->pFirstEntry = 0;
  pTab->pLastEntry = 0;
  fclose(pTab->pWriteFd);
  pTab->pWriteFd = 0;
  pTab->szCurrent = 0;
  pTab->szOrig = 0;
}

static int zipfileBegin(sqlite3_vtab *pVtab){
  ZipfileTab *pTab = (ZipfileTab*)pVtab;
  int rc = SQLITE_OK;

  assert( pTab->pWriteFd==0 );

  /* This table is only writable if a default archive path was specified 
  ** as part of the CREATE VIRTUAL TABLE statement. */
  if( pTab->zFile==0 ){
    pTab->base.zErrMsg = sqlite3_mprintf(
        "zipfile: writing requires a default archive"
    );
    return SQLITE_ERROR;
  }

  /* Open a write fd on the file. Also load the entire central directory
  ** structure into memory. During the transaction any new file data is 
  ** appended to the archive file, but the central directory is accumulated
  ** in main-memory until the transaction is committed.  */
  pTab->pWriteFd = fopen(pTab->zFile, "ab+");
  if( pTab->pWriteFd==0 ){
    pTab->base.zErrMsg = sqlite3_mprintf(
        "zipfile: failed to open file %s for writing", pTab->zFile
    );
    rc = SQLITE_ERROR;
  }else{
    fseek(pTab->pWriteFd, 0, SEEK_END);
    pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
    rc = zipfileLoadDirectory(pTab);
  }

  if( rc!=SQLITE_OK ){
    zipfileCleanupTransaction(pTab);
  }

  return rc;
}

static int zipfileCommit(sqlite3_vtab *pVtab){
  ZipfileTab *pTab = (ZipfileTab*)pVtab;
  int rc = SQLITE_OK;
  if( pTab->pWriteFd ){
    i64 iOffset = pTab->szCurrent;
    ZipfileEntry *p;
    ZipfileEOCD eocd;
    int nEntry = 0;

    /* Write out all undeleted entries */
    for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){
      if( p->bDeleted ) continue;
      rc = zipfileAppendData(pTab, p->aCdsEntry, p->nCdsEntry);
      nEntry++;
    }

    /* Write out the EOCD record */
    eocd.iDisk = 0;
    eocd.iFirstDisk = 0;
    eocd.nEntry = (u16)nEntry;
    eocd.nEntryTotal = (u16)nEntry;
    eocd.nSize = (u32)(pTab->szCurrent - iOffset);
    eocd.iOffset = (u32)iOffset;
    rc = zipfileAppendEOCD(pTab, &eocd);

    zipfileCleanupTransaction(pTab);
  }
  return rc;
}

static int zipfileRollback(sqlite3_vtab *pVtab){
  return zipfileCommit(pVtab);
}

static ZipfileCsr *zipfileFindCursor(ZipfileTab *pTab, i64 iId){
  ZipfileCsr *pCsr;
  for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){
    if( iId==pCsr->iId ) break;
  }
  return pCsr;
}

static void zipfileFunctionCds(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  ZipfileCsr *pCsr;
  ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context);
  assert( argc>0 );

  pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0]));
  if( pCsr ){
    ZipfileCDS *p = &pCsr->cds;
    char *zRes = sqlite3_mprintf("{"
        "\"version-made-by\" : %u, "
        "\"version-to-extract\" : %u, "
        "\"flags\" : %u, "
        "\"compression\" : %u, "
        "\"time\" : %u, "
        "\"date\" : %u, "
        "\"crc32\" : %u, "
        "\"compressed-size\" : %u, "
        "\"uncompressed-size\" : %u, "
        "\"file-name-length\" : %u, "
        "\"extra-field-length\" : %u, "
        "\"file-comment-length\" : %u, "
        "\"disk-number-start\" : %u, "
        "\"internal-attr\" : %u, "
        "\"external-attr\" : %u, "
        "\"offset\" : %u }",
        (u32)p->iVersionMadeBy, (u32)p->iVersionExtract,
        (u32)p->flags, (u32)p->iCompression,
        (u32)p->mTime, (u32)p->mDate,
        (u32)p->crc32, (u32)p->szCompressed,
        (u32)p->szUncompressed, (u32)p->nFile,
        (u32)p->nExtra, (u32)p->nComment,
        (u32)p->iDiskStart, (u32)p->iInternalAttr,
        (u32)p->iExternalAttr, (u32)p->iOffset
    );

    if( zRes==0 ){
      sqlite3_result_error_nomem(context);
    }else{
      sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
      sqlite3_free(zRes);
    }
  }
}


/*
** xFindFunction method.
*/
static int zipfileFindFunction(
  sqlite3_vtab *pVtab,            /* Virtual table handle */
  int nArg,                       /* Number of SQL function arguments */
  const char *zName,              /* Name of SQL function */
  void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
  void **ppArg                    /* OUT: User data for *pxFunc */
){
  if( nArg>0 ){
    if( sqlite3_stricmp("zipfile_cds", zName)==0 ){
      *pxFunc = zipfileFunctionCds;
      *ppArg = (void*)pVtab;
      return 1;
    }
  }

  return 0;
}

/*
** Register the "zipfile" virtual table.
*/
static int zipfileRegister(sqlite3 *db){
  static sqlite3_module zipfileModule = {
    1,                         /* iVersion */
    zipfileConnect,            /* xCreate */
    zipfileConnect,            /* xConnect */
    zipfileBestIndex,          /* xBestIndex */
    zipfileDisconnect,         /* xDisconnect */
    zipfileDisconnect,         /* xDestroy */
    zipfileOpen,               /* xOpen - open a cursor */
    zipfileClose,              /* xClose - close a cursor */
    zipfileFilter,             /* xFilter - configure scan constraints */
    zipfileNext,               /* xNext - advance a cursor */
    zipfileEof,                /* xEof - check for end of scan */
    zipfileColumn,             /* xColumn - read data */
    zipfileRowid,              /* xRowid - read data */
    zipfileUpdate,             /* xUpdate */
    zipfileBegin,              /* xBegin */
    0,                         /* xSync */
    zipfileCommit,             /* xCommit */
    zipfileRollback,           /* xRollback */
    zipfileFindFunction,       /* xFindMethod */
    0,                         /* xRename */
  };

  int rc = sqlite3_create_module(db, "zipfile"  , &zipfileModule, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_overload_function(db, "zipfile_cds", -1);
  }
  return rc;
}
#else         /* SQLITE_OMIT_VIRTUALTABLE */
# define zipfileRegister(x) SQLITE_OK
#endif

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_zipfile_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  return zipfileRegister(db);
}
Added ext/rbu/rbumulti.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
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
# 2018 January 11
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains tests of multiple RBU operations running
# concurrently within the same process. 
#

source [file join [file dirname [info script]] rbu_common.tcl]
set ::testprefix rbumulti

db close
sqlite3_shutdown
sqlite3_config_uri 1

autoinstall_test_functions

proc build_db {db} {
  $db eval {
    CREATE TABLE t1(a PRIMARY KEY, b, c);
    CREATE INDEX i1 ON t1(b);
    CREATE INDEX i2 ON t1(c);

    WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 )
    INSERT INTO t1 
    SELECT randomblob(10), randomblob(100), randomblob(100) FROM s;
  }
}

proc build_rbu {db} {
  $db eval {
    CREATE TABLE data_t1(a, b, c, rbu_control);
    WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 )
    INSERT INTO data_t1 
    SELECT randomblob(10), randomblob(100), randomblob(100), 0 FROM s;
  }
}

proc step_rbu2 {bOpenClose openr1 openr2} {

  forcedelete teststate.db1
  forcedelete teststate.db2

  if {$bOpenClose!=0 && $bOpenClose!=1} { error $bOpenClose }
  if {$bOpenClose==0} {
    eval $openr1 
    eval $openr2 
  }

  set b1 0
  set b2 0

  while {$b1==0 || $b2==0} {
    if {$bOpenClose==1} {
      if {$b1==0} { eval $openr1 teststate.db1 }
      if {$b2==0} { eval $openr2 teststate.db2 }
    }
    if {$b1==0} {
      set rc1 [r1 step]
      if {$rc1 != "SQLITE_OK"} { set b1 1 }
    }
    if {$b2==0} {
      set rc2 [r2 step]
      if {$rc2 != "SQLITE_OK"} { set b2 1 }
    }
    if {$bOpenClose==1} {
      if {$b1==0} { r1 close }
      if {$b2==0} { r2 close }
    }
  }

  set rc1 [r1 close]
  set rc2 [r2 close]

  list $rc1 $rc2
}


for {set i 0} {$i<=3} {incr i} {

  if {$i & 0x01} {
    sqlite3rbu_create_vfs -default myrbu ""
  }
  set bOpenClose [expr $i>>1]

  forcedelete test.db
  forcedelete test.db2
  forcedelete rbu.db
  forcedelete rbu.db2
  
  do_test 1.$i.0 {
    sqlite3 db test.db
    sqlite3 db2 test.db2
    build_db db
    build_db db2
  
    sqlite3 rbu1 rbu.db
    sqlite3 rbu2 rbu.db2
  
    build_rbu rbu1
    build_rbu rbu2
  
    rbu1 close
    rbu2 close
  } {}

  set m1 [db eval {SELECT md5sum(a, b, c) FROM t1}]
  set m2 [db2 eval {SELECT md5sum(a, b, c) FROM t1}]
  
  do_test 1.$i.1 {
    step_rbu2 $bOpenClose {
      sqlite3rbu r1 test.db rbu.db
    } {
      sqlite3rbu r2 test.db2 rbu.db2
    }
  } {SQLITE_DONE SQLITE_DONE}
  
  do_execsql_test -db db  1.$i.2.1 { PRAGMA integrity_check } ok
  do_execsql_test -db db2 1.$i.2.2 { PRAGMA integrity_check } ok

  do_execsql_test -db db  1.$i.3.1 { SELECT md5sum(a, b, c)==$m1 FROM t1 } 0
  do_execsql_test -db db2 1.$i.3.2 { SELECT md5sum(a, b, c)==$m2 FROM t1 } 0
  
  catch { db close }
  catch { db2 close }
  #-----------------------------------------------------------------------
  forcedelete test.db2
  forcedelete test.db
  forcedelete rbu.db2
  
  do_test 1.$i.4 {
    sqlite3 db test.db
    sqlite3 db2 test.db2
    build_db db
    build_db db2
    sqlite3 rbu2 rbu.db2
    build_rbu rbu2
    rbu2 close
  } {}

  set m1 [db eval {SELECT md5sum(a, b, c) FROM t1}]
  set m2 [db2 eval {SELECT md5sum(a, b, c) FROM t1}]

  do_test 1.$i.5 {
    step_rbu2 $bOpenClose {
      sqlite3rbu_vacuum r1 test.db
    } {
      sqlite3rbu r2 test.db2 rbu.db2
    }
  } {SQLITE_DONE SQLITE_DONE}

  do_execsql_test -db db  1.$i.6.1 { SELECT md5sum(a, b, c)==$m1 FROM t1 } 1
  do_execsql_test -db db2 1.$i.6.2 { SELECT md5sum(a, b, c)==$m2 FROM t1 } 0

  do_execsql_test -db db  1.$i.7.1 { PRAGMA integrity_check } ok
  do_execsql_test -db db2 1.$i.7.2 { PRAGMA integrity_check } ok

  catch { db close }
  catch { db2 close }
  if {$i & 0x01} {
    sqlite3rbu_destroy_vfs myrbu
  }

}


finish_test

Changes to ext/rtree/rtree.c.
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
**   3. The remainder of the node contains the node entries. Each entry
**      consists of a single 8-byte integer followed by an even number
**      of 4-byte coordinates. For leaf nodes the integer is the rowid
**      of a record. For internal nodes it is the node number of a
**      child page.
*/

#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)


#ifndef SQLITE_CORE
  #include "sqlite3ext.h"
  SQLITE_EXTENSION_INIT1
#else
  #include "sqlite3.h"
#endif







|
>







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
**   3. The remainder of the node contains the node entries. Each entry
**      consists of a single 8-byte integer followed by an even number
**      of 4-byte coordinates. For leaf nodes the integer is the rowid
**      of a record. For internal nodes it is the node number of a
**      child page.
*/

#if !defined(SQLITE_CORE) \
  || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE))

#ifndef SQLITE_CORE
  #include "sqlite3ext.h"
  SQLITE_EXTENSION_INIT1
#else
  #include "sqlite3.h"
#endif
Changes to ext/rtree/rtree.h.
10
11
12
13
14
15
16




17
18
19
20
21
22
23
**
******************************************************************************
**
** This header file is used by programs that want to link against the
** RTREE library.  All it does is declare the sqlite3RtreeInit() interface.
*/
#include "sqlite3.h"





#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

int sqlite3RtreeInit(sqlite3 *db);








>
>
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
**
******************************************************************************
**
** This header file is used by programs that want to link against the
** RTREE library.  All it does is declare the sqlite3RtreeInit() interface.
*/
#include "sqlite3.h"

#ifdef SQLITE_OMIT_VIRTUALTABLE
# undef SQLITE_ENABLE_RTREE
#endif

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

int sqlite3RtreeInit(sqlite3 *db);

Changes to ext/session/sessionD.test.
217
218
219
220
221
222
223

































224
225
do_test 4.2.2 {
  sqlite3session S db main
  S attach t2
  list [catch { S diff ixua t2 } msg] $msg
} {1 {SQLITE_SCHEMA - table schemas do not match}}
S delete


































finish_test








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


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
255
256
257
258
do_test 4.2.2 {
  sqlite3session S db main
  S attach t2
  list [catch { S diff ixua t2 } msg] $msg
} {1 {SQLITE_SCHEMA - table schemas do not match}}
S delete

do_test 4.3.1 {
  sqlite3session S db main
  S attach t4
  execsql { CREATE TABLE t4(i PRIMARY KEY, b) }
  list [catch { S diff ixua t4 } msg] $msg
} {1 {SQLITE_SCHEMA - table schemas do not match}}
S delete
do_catchsql_test 4.3.2 {
  SELECT * FROM ixua.t4;
} {1 {no such table: ixua.t4}}

do_test 4.4.1 {
  sqlite3session S db main
  S attach sqlite_stat1
  execsql { ANALYZE }
  execsql { DROP TABLE ixua.sqlite_stat1 }
  list [catch { S diff ixua sqlite_stat1 } msg] $msg
} {1 {SQLITE_SCHEMA - table schemas do not match}}
S delete
do_catchsql_test 4.4.2 {
  SELECT * FROM ixua.sqlite_stat1;
} {1 {no such table: ixua.sqlite_stat1}}

do_test 4.5.1 {
  sqlite3session S db main
  S attach t8
  list [catch { S diff ixua t8 } msg] $msg
} {0 {}}
S delete
do_catchsql_test 4.5.2 {
  SELECT * FROM ixua.i8;
} {1 {no such table: ixua.i8}}

finish_test

Changes to ext/session/sessionG.test.
168
169
170
171
172
173
174


































175
176
177

    UPDATE t2 SET b=3 WHERE a=3;
    UPDATE t2 SET b=2 WHERE a=2;
    UPDATE t2 SET b=1 WHERE a=1;
  }
  compare_db db db2
} {}



































finish_test








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



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

    UPDATE t2 SET b=3 WHERE a=3;
    UPDATE t2 SET b=2 WHERE a=2;
    UPDATE t2 SET b=1 WHERE a=1;
  }
  compare_db db db2
} {}

#-------------------------------------------------------------------------
reset_db 
catch { db2 close }
forcedelete test.db2
sqlite3 db2 test.db2

do_execsql_test 5.0.1 {
  CREATE TABLE t1(a PRIMARY KEY, b, c);
  CREATE TABLE t2(a, b, c PRIMARY KEY);
  CREATE TABLE t3(a, b PRIMARY KEY, c);
}
do_execsql_test -db db2 5.0.2 {
  CREATE TABLE t1(a PRIMARY KEY, b, c);
  CREATE TABLE t2(a, b, c);
  CREATE TABLE t3(a, b PRIMARY KEY, c);
}

do_test 5.1 {
  do_then_apply_sql {
    INSERT INTO t1 VALUES(1, 2, 3);
    INSERT INTO t2 VALUES(4, 5, 6);
    INSERT INTO t3 VALUES(7, 8, 9);
  }

  db2 eval {
    SELECT * FROM t1;
    SELECT * FROM t2;
    SELECT * FROM t3;
  }
} {1 2 3 7 8 9}




finish_test

Added ext/session/sessionH.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
# 2018 January 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.
#
#***********************************************************************
#

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}
set testprefix sessionH

forcedelete test.db2
sqlite3 db2 test.db2

do_test 1.0 {
  do_common_sql {
    CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b));
  }
  do_then_apply_sql {
    WITH s(i) AS (
      VALUES(1) UNION ALL SELECT i+1 FROM s WHERe i<10000
    )
    INSERT INTO t1 SELECT 'abcde', randomblob(16), i FROM s;
  }
  compare_db db db2
} {}


finish_test

Changes to ext/session/sessionat.test.
237
238
239
240
241
242
243




244
245
  do_test $tn.6.3 {
    sqlite3changeset_apply db $cinv xConflict
    execsql { SELECT * FROM t7 }
  } {1 1 ccc 2 2 ccc 3 3 ccc}
}]
}






finish_test







>
>
>
>


237
238
239
240
241
242
243
244
245
246
247
248
249
  do_test $tn.6.3 {
    sqlite3changeset_apply db $cinv xConflict
    execsql { SELECT * FROM t7 }
  } {1 1 ccc 2 2 ccc 3 3 ccc}
}]
}

catch { db close }
catch { db2 close }
sqlite3_shutdown
test_sqlite3_log

finish_test
Added ext/session/sessionstat1.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
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
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
# 2018 January 12
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

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}

set testprefix sessionstat1

do_execsql_test 1.0 {
  CREATE TABLE t1(a PRIMARY KEY, b, c);
  CREATE INDEX t1b ON t1(b);
  CREATE INDEX t1c ON t1(c);

  WITH s(i) AS (
    SELECT 0 UNION ALL SELECT i+1 FROM s WHERE (i+1)<32
  )
  INSERT INTO t1 SELECT i, i%8, i%2 FROM s;
}

do_iterator_test 1.1 {} {
  ANALYZE
} {
  {INSERT sqlite_stat1 0 XX. {} {t t1 t sqlite_autoindex_t1_1 t {32 1}}}
  {INSERT sqlite_stat1 0 XX. {} {t t1 t t1b t {32 4}}} 
  {INSERT sqlite_stat1 0 XX. {} {t t1 t t1c t {32 16}}}
}

do_execsql_test 1.2 {
  WITH s(i) AS (
    SELECT 32 UNION ALL SELECT i+1 FROM s WHERE (i+1)<64
  )
  INSERT INTO t1 SELECT i, i%8, i%2 FROM s;
}

do_iterator_test 1.3 {} {
  ANALYZE
} {
  {UPDATE sqlite_stat1 0 XX. {t t1 t sqlite_autoindex_t1_1 t {32 1}} {{} {} {} {} t {64 1}}} 
  {UPDATE sqlite_stat1 0 XX. {t t1 t t1b t {32 4}} {{} {} {} {} t {64 8}}} 
  {UPDATE sqlite_stat1 0 XX. {t t1 t t1c t {32 16}} {{} {} {} {} t {64 32}}}
}

do_iterator_test 1.5 {} {
  DROP INDEX t1b;
} {
  {DELETE sqlite_stat1 0 XX. {t t1 t t1b t {64 8}} {}}
}

do_iterator_test 1.6 {} {
  DROP TABLE t1;
} {
  {DELETE sqlite_stat1 0 XX. {t t1 t sqlite_autoindex_t1_1 t {64 1}} {}}
  {DELETE sqlite_stat1 0 XX. {t t1 t t1c t {64 32}} {}}
}

#-------------------------------------------------------------------------
#
catch { db2 close }
forcedelete test.db2
sqlite3 db2 test.db2

do_test 2.0 {
  do_common_sql {
    CREATE TABLE t1(a PRIMARY KEY, b, c);
    CREATE INDEX t1b ON t1(b);
    CREATE INDEX t1c ON t1(c);
    ANALYZE;
  }
} {}

do_test 2.1 {
  do_then_apply_sql {
    WITH s(i) AS (
        SELECT 0 UNION ALL SELECT i+1 FROM s WHERE (i+1)<32
    )
    INSERT INTO t1 SELECT i, i%8, i%2 FROM s;
    ANALYZE;
  }
} {}

do_execsql_test -db db2 2.2 {
  SELECT * FROM sqlite_stat1
} {
  t1 sqlite_autoindex_t1_1 {32 1} 
  t1 t1b {32 4} 
  t1 t1c {32 16}
}

do_test 2.3 {
  do_then_apply_sql { DROP INDEX t1c }
} {}

do_execsql_test -db db2 2.4 {
  SELECT * FROM sqlite_stat1
} {
  t1 sqlite_autoindex_t1_1 {32 1} 
  t1 t1b {32 4} 
}

do_test 2.3 {
  do_then_apply_sql { DROP TABLE t1 }
} {}

do_execsql_test -db db2 2.4 {
  SELECT * FROM sqlite_stat1
} {
}

do_execsql_test -db db2 2.5 { SELECT count(*) FROM t1 } 32

#-------------------------------------------------------------------------
db2 close
forcedelete test.db2
reset_db
sqlite3 db2 test.db2

do_test 3.0 {
  do_common_sql {
    CREATE TABLE t1(a, b, c);
    ANALYZE;
    DELETE FROM sqlite_stat1;
  }
  execsql {
    INSERT INTO t1 VALUES(1, 1, 1);
    INSERT INTO t1 VALUES(2, 2, 2);
    INSERT INTO t1 VALUES(3, 3, 3);
    INSERT INTO t1 VALUES(4, 4, 4);
  }
} {} 

do_iterator_test 3.1 {} {
  ANALYZE
} {
  {INSERT sqlite_stat1 0 XX. {} {t t1 b {} t 4}}
}
db null null
db2 null null
do_execsql_test 3.2 {
  SELECT * FROM sqlite_stat1;
} {t1 null 4}
do_test 3.3 {
  execsql { DELETE FROM sqlite_stat1 }
  do_then_apply_sql { ANALYZE }
  execsql { SELECT * FROM sqlite_stat1 } db2
} {t1 null 4}
do_test 3.4 {
  execsql { INSERT INTO t1 VALUES(5,5,5) }
  do_then_apply_sql { ANALYZE }
  execsql { SELECT * FROM sqlite_stat1 } db2
} {t1 null 5}
do_test 3.5 {
  do_then_apply_sql { DROP TABLE t1 }
  execsql { SELECT * FROM sqlite_stat1 } db2
} {}

do_test 3.6.1 {
  execsql { 
    CREATE TABLE t1(a, b, c);
    CREATE TABLE t2(x, y, z);
    INSERT INTO t1 VALUES(1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5);
    INSERT INTO t2 SELECT * FROM t1;
    DELETE FROM sqlite_stat1;
  }
  sqlite3session S db main
  S attach sqlite_stat1
  execsql { ANALYZE }
} {}
do_changeset_test 3.6.2 S {
  {INSERT sqlite_stat1 0 XX. {} {t t2 b {} t 5}}
  {INSERT sqlite_stat1 0 XX. {} {t t1 b {} t 5}}
}
do_changeset_invert_test 3.6.3 S {
  {DELETE sqlite_stat1 0 XX. {t t2 b {} t 5} {}}
  {DELETE sqlite_stat1 0 XX. {t t1 b {} t 5} {}}
}
do_test 3.6.4 { S delete } {}

proc sql_changeset_concat {args} {
  foreach sql $args {
    sqlite3session S db main
    S attach sqlite_stat1
    execsql $sql
    set change [S changeset]
    S delete

    if {[info vars ret]!=""} {
      set ret [sqlite3changeset_concat $ret $change]
    } else {
      set ret $change
    }
  }

  changeset_to_list $ret
}

proc do_scc_test {tn args} {
  uplevel [list \
    do_test $tn [concat sql_changeset_concat [lrange $args 0 end-1]] \
    [list {*}[ lindex $args end ]]
  ]
}

do_execsql_test 3.7.0 {
  DELETE FROM sqlite_stat1;
}
do_scc_test 3.7.1 {
  ANALYZE;
} {
  INSERT INTO t2 VALUES(6,6,6);
  ANALYZE;
} {
  {INSERT sqlite_stat1 0 XX. {} {t t1 b {} t 5}}
  {INSERT sqlite_stat1 0 XX. {} {t t2 b {} t 6}}
}

#-------------------------------------------------------------------------
catch { db2 close }
reset_db
forcedelete test.db2
sqlite3 db2 test.db2

do_test 4.1.0 {
  do_common_sql {
    CREATE TABLE t1(a, b);
    CREATE INDEX i1 ON t1(a);
    CREATE INDEX i2 ON t1(b);
    INSERT INTO t1 VALUES(1,1), (2,2);
    ANALYZE;
  }
  execsql { DELETE FROM sqlite_stat1 }
} {}

do_test 4.1.1 {
  execsql { INSERT INTO t1 VALUES(3,3); }
  set C [changeset_from_sql {ANALYZE}]
  set ::c [list]
  proc xConflict {args} {
    lappend ::c $args
    return "OMIT"
  }
  sqlite3changeset_apply db2 $C xConflict
  set ::c
} [list {*}{
  {INSERT sqlite_stat1 CONFLICT {t t1 t i1 t {3 1}} {t t1 t i1 t {2 1}}}
  {INSERT sqlite_stat1 CONFLICT {t t1 t i2 t {3 1}} {t t1 t i2 t {2 1}}}
}]

do_execsql_test -db db2 4.1.2 {
  SELECT * FROM sqlite_stat1 ORDER BY 1,2;
} {t1 i1 {2 1} t1 i2 {2 1}}

do_test 4.1.3 {
  proc xConflict {args} {
    return "REPLACE"
  }
  sqlite3changeset_apply db2 $C xConflict
  execsql { SELECT * FROM sqlite_stat1 ORDER BY 1,2 } db2
} {t1 i1 {3 1} t1 i2 {3 1}}

do_test 4.2.0 {
  do_common_sql { 
    DROP TABLE t1;
    CREATE TABLE t3(x,y);
    INSERT INTO t3 VALUES('a','a');
    INSERT INTO t3 VALUES('b','b');
    ANALYZE;
  }
  execsql { DELETE FROM sqlite_stat1 }
} {}
do_test 4.2.1 {
  execsql { INSERT INTO t3 VALUES('c','c'); }
  set C [changeset_from_sql {ANALYZE}]
  set ::c [list]
  proc xConflict {args} {
    lappend ::c $args
    return "OMIT"
  }
  sqlite3changeset_apply db2 $C xConflict
  set ::c
} [list {*}{
  {INSERT sqlite_stat1 CONFLICT {t t3 b {} t 3} {t t3 b {} t 2}}
}]

db2 null null
do_execsql_test -db db2 4.2.2 {
  SELECT * FROM sqlite_stat1 ORDER BY 1,2;
} {t3 null 2}

do_test 4.2.3 {
  proc xConflict {args} {
    return "REPLACE"
  }
  sqlite3changeset_apply db2 $C xConflict
  execsql { SELECT * FROM sqlite_stat1 ORDER BY 1,2 } db2
} {t3 null 3}

finish_test

Changes to ext/session/sqlite3session.c.
42
43
44
45
46
47
48

49
50
51
52
53
54
55
  char *zDb;                      /* Name of database session is attached to */
  int bEnable;                    /* True if currently recording */
  int bIndirect;                  /* True if all changes are indirect */
  int bAutoAttach;                /* True to auto-attach tables */
  int rc;                         /* Non-zero if an error has occurred */
  void *pFilterCtx;               /* First argument to pass to xTableFilter */
  int (*xTableFilter)(void *pCtx, const char *zTab);

  sqlite3_session *pNext;         /* Next session object on same db. */
  SessionTable *pTable;           /* List of attached tables */
  SessionHook hook;               /* APIs to grab new and old data with */
};

/*
** Instances of this structure are used to build strings or binary records.







>







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  char *zDb;                      /* Name of database session is attached to */
  int bEnable;                    /* True if currently recording */
  int bIndirect;                  /* True if all changes are indirect */
  int bAutoAttach;                /* True to auto-attach tables */
  int rc;                         /* Non-zero if an error has occurred */
  void *pFilterCtx;               /* First argument to pass to xTableFilter */
  int (*xTableFilter)(void *pCtx, const char *zTab);
  sqlite3_value *pZeroBlob;       /* Value containing X'' */
  sqlite3_session *pNext;         /* Next session object on same db. */
  SessionTable *pTable;           /* List of attached tables */
  SessionHook hook;               /* APIs to grab new and old data with */
};

/*
** Instances of this structure are used to build strings or binary records.
109
110
111
112
113
114
115

116
117
118
119
120
121
122
** a subset of the initial values that the modified row contained at the
** start of the session. Or no initial values if the row was inserted.
*/
struct SessionTable {
  SessionTable *pNext;
  char *zName;                    /* Local name of table */
  int nCol;                       /* Number of columns in table zName */

  const char **azCol;             /* Column names */
  u8 *abPK;                       /* Array of primary key flags */
  int nEntry;                     /* Total number of entries in hash table */
  int nChange;                    /* Size of apChange[] array */
  SessionChange **apChange;       /* Hash table buckets */
};








>







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
** a subset of the initial values that the modified row contained at the
** start of the session. Or no initial values if the row was inserted.
*/
struct SessionTable {
  SessionTable *pNext;
  char *zName;                    /* Local name of table */
  int nCol;                       /* Number of columns in table zName */
  int bStat1;                     /* True if this is sqlite_stat1 */
  const char **azCol;             /* Column names */
  u8 *abPK;                       /* Array of primary key flags */
  int nEntry;                     /* Total number of entries in hash table */
  int nChange;                    /* Size of apChange[] array */
  SessionChange **apChange;       /* Hash table buckets */
};

492
493
494
495
496
497
498

499
500
501
502
503
504
505
          z = (const u8 *)sqlite3_value_blob(pVal);
        }
        n = sqlite3_value_bytes(pVal);
        if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
        h = sessionHashAppendBlob(h, n, z);
      }else{
        assert( eType==SQLITE_NULL );

        *pbNullPK = 1;
      }
    }
  }

  *piHash = (h % pTab->nChange);
  return SQLITE_OK;







>







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
          z = (const u8 *)sqlite3_value_blob(pVal);
        }
        n = sqlite3_value_bytes(pVal);
        if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
        h = sessionHashAppendBlob(h, n, z);
      }else{
        assert( eType==SQLITE_NULL );
        assert( pTab->bStat1==0 || i!=1 );
        *pbNullPK = 1;
      }
    }
  }

  *piHash = (h % pTab->nChange);
  return SQLITE_OK;
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
        if( eType==SQLITE_TEXT ){
          z = sqlite3_value_text(pVal);
        }else{
          z = sqlite3_value_blob(pVal);
        }
        if( memcmp(a, z, n) ) return 0;
        a += n;
        break;
      }
    }
  }

  return 1;
}








<







837
838
839
840
841
842
843

844
845
846
847
848
849
850
        if( eType==SQLITE_TEXT ){
          z = sqlite3_value_text(pVal);
        }else{
          z = sqlite3_value_blob(pVal);
        }
        if( memcmp(a, z, n) ) return 0;
        a += n;

      }
    }
  }

  return 1;
}

890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
  }

  return SQLITE_OK;
}

/*
** This function queries the database for the names of the columns of table
** zThis, in schema zDb. It is expected that the table has nCol columns. If
** not, SQLITE_SCHEMA is returned and none of the output variables are
** populated.
**
** Otherwise, if they are not NULL, variable *pnCol is set to the number
** of columns in the database table and variable *pzTab is set to point to a
** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
** point to an array of pointers to column names. And *pabPK (again, if not
** NULL) is set to point to an array of booleans - true if the corresponding
** column is part of the primary key.
**
** For example, if the table is declared as:
**
**     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
**
** Then the four output variables are populated as follows:
**
**     *pnCol  = 4
**     *pzTab  = "tbl1"
**     *pazCol = {"w", "x", "y", "z"}
**     *pabPK  = {1, 0, 0, 1}
**
** All returned buffers are part of the same single allocation, which must
** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then
** pointer *pazCol should be freed to release all memory. Otherwise, pointer
** *pabPK. It is illegal for both pazCol and pabPK to be NULL.
*/
static int sessionTableInfo(
  sqlite3 *db,                    /* Database connection */
  const char *zDb,                /* Name of attached database (e.g. "main") */
  const char *zThis,              /* Table name */
  int *pnCol,                     /* OUT: number of columns */
  const char **pzTab,             /* OUT: Copy of zThis */







|
<
<




















|
<
<







892
893
894
895
896
897
898
899


900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920


921
922
923
924
925
926
927
  }

  return SQLITE_OK;
}

/*
** This function queries the database for the names of the columns of table
** zThis, in schema zDb.


**
** Otherwise, if they are not NULL, variable *pnCol is set to the number
** of columns in the database table and variable *pzTab is set to point to a
** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
** point to an array of pointers to column names. And *pabPK (again, if not
** NULL) is set to point to an array of booleans - true if the corresponding
** column is part of the primary key.
**
** For example, if the table is declared as:
**
**     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
**
** Then the four output variables are populated as follows:
**
**     *pnCol  = 4
**     *pzTab  = "tbl1"
**     *pazCol = {"w", "x", "y", "z"}
**     *pabPK  = {1, 0, 0, 1}
**
** All returned buffers are part of the same single allocation, which must
** be freed using sqlite3_free() by the caller


*/
static int sessionTableInfo(
  sqlite3 *db,                    /* Database connection */
  const char *zDb,                /* Name of attached database (e.g. "main") */
  const char *zThis,              /* Table name */
  int *pnCol,                     /* OUT: number of columns */
  const char **pzTab,             /* OUT: Copy of zThis */
940
941
942
943
944
945
946















947

948
949
950
951
952
953
954
  u8 *pAlloc = 0;
  char **azCol = 0;
  u8 *abPK = 0;

  assert( pazCol && pabPK );

  nThis = sqlite3Strlen30(zThis);















  zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);

  if( !zPragma ) return SQLITE_NOMEM;

  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
  sqlite3_free(zPragma);
  if( rc!=SQLITE_OK ) return rc;

  nByte = nThis + 1;







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







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
  u8 *pAlloc = 0;
  char **azCol = 0;
  u8 *abPK = 0;

  assert( pazCol && pabPK );

  nThis = sqlite3Strlen30(zThis);
  if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
    rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
    if( rc==SQLITE_OK ){
      /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
      zPragma = sqlite3_mprintf(
          "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
          "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
          "SELECT 2, 'stat', '', 0, '', 0"
      );
    }else if( rc==SQLITE_ERROR ){
      zPragma = sqlite3_mprintf("");
    }else{
      return rc;
    }
  }else{
    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
  }
  if( !zPragma ) return SQLITE_NOMEM;

  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
  sqlite3_free(zPragma);
  if( rc!=SQLITE_OK ) return rc;

  nByte = nThis + 1;
1032
1033
1034
1035
1036
1037
1038


1039
1040

1041
1042









































1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059

1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077



















1078
1079
1080
1081
1082
1083
1084
      int i;
      for(i=0; i<pTab->nCol; i++){
        if( abPK[i] ){
          pTab->abPK = abPK;
          break;
        }
      }


    }
  }

  return (pSession->rc || pTab->abPK==0);
}










































/*
** This function is only called from with a pre-update-hook reporting a 
** change on table pTab (attached to session pSession). The type of change
** (UPDATE, INSERT, DELETE) is specified by the first argument.
**
** Unless one is already present or an error occurs, an entry is added
** to the changed-rows hash table associated with table pTab.
*/
static void sessionPreupdateOneChange(
  int op,                         /* One of SQLITE_UPDATE, INSERT, DELETE */
  sqlite3_session *pSession,      /* Session object pTab is attached to */
  SessionTable *pTab              /* Table that change applies to */
){
  int iHash; 
  int bNull = 0; 
  int rc = SQLITE_OK;


  if( pSession->rc ) return;

  /* Load table details if required */
  if( sessionInitTable(pSession, pTab) ) return;

  /* Check the number of columns in this xPreUpdate call matches the 
  ** number of columns in the table.  */
  if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
    pSession->rc = SQLITE_SCHEMA;
    return;
  }

  /* Grow the hash table if required */
  if( sessionGrowHash(0, pTab) ){
    pSession->rc = SQLITE_NOMEM;
    return;
  }




















  /* Calculate the hash-key for this change. If the primary key of the row
  ** includes a NULL value, exit early. Such changes are ignored by the
  ** session module. */
  rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
  if( rc!=SQLITE_OK ) goto error_out;








>
>
|
|
>


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

















>


















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







1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
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
      int i;
      for(i=0; i<pTab->nCol; i++){
        if( abPK[i] ){
          pTab->abPK = abPK;
          break;
        }
      }
      if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
        pTab->bStat1 = 1;
      }
    }
  }
  return (pSession->rc || pTab->abPK==0);
}

/*
** Versions of the four methods in object SessionHook for use with the
** sqlite_stat1 table. The purpose of this is to substitute a zero-length
** blob each time a NULL value is read from the "idx" column of the
** sqlite_stat1 table.
*/
typedef struct SessionStat1Ctx SessionStat1Ctx;
struct SessionStat1Ctx {
  SessionHook hook;
  sqlite3_session *pSession;
};
static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){
  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
  sqlite3_value *pVal = 0;
  int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal);
  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
    pVal = p->pSession->pZeroBlob;
  }
  *ppVal = pVal;
  return rc;
}
static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){
  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
  sqlite3_value *pVal = 0;
  int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal);
  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
    pVal = p->pSession->pZeroBlob;
  }
  *ppVal = pVal;
  return rc;
}
static int sessionStat1Count(void *pCtx){
  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
  return p->hook.xCount(p->hook.pCtx);
}
static int sessionStat1Depth(void *pCtx){
  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
  return p->hook.xDepth(p->hook.pCtx);
}


/*
** This function is only called from with a pre-update-hook reporting a 
** change on table pTab (attached to session pSession). The type of change
** (UPDATE, INSERT, DELETE) is specified by the first argument.
**
** Unless one is already present or an error occurs, an entry is added
** to the changed-rows hash table associated with table pTab.
*/
static void sessionPreupdateOneChange(
  int op,                         /* One of SQLITE_UPDATE, INSERT, DELETE */
  sqlite3_session *pSession,      /* Session object pTab is attached to */
  SessionTable *pTab              /* Table that change applies to */
){
  int iHash; 
  int bNull = 0; 
  int rc = SQLITE_OK;
  SessionStat1Ctx stat1 = {0};

  if( pSession->rc ) return;

  /* Load table details if required */
  if( sessionInitTable(pSession, pTab) ) return;

  /* Check the number of columns in this xPreUpdate call matches the 
  ** number of columns in the table.  */
  if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
    pSession->rc = SQLITE_SCHEMA;
    return;
  }

  /* Grow the hash table if required */
  if( sessionGrowHash(0, pTab) ){
    pSession->rc = SQLITE_NOMEM;
    return;
  }

  if( pTab->bStat1 ){
    stat1.hook = pSession->hook;
    stat1.pSession = pSession;
    pSession->hook.pCtx = (void*)&stat1;
    pSession->hook.xNew = sessionStat1New;
    pSession->hook.xOld = sessionStat1Old;
    pSession->hook.xCount = sessionStat1Count;
    pSession->hook.xDepth = sessionStat1Depth;
    if( pSession->pZeroBlob==0 ){
      sqlite3_value *p = sqlite3ValueNew(0);
      if( p==0 ){
        rc = SQLITE_NOMEM;
        goto error_out;
      }
      sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC);
      pSession->pZeroBlob = p;
    }
  }

  /* Calculate the hash-key for this change. If the primary key of the row
  ** includes a NULL value, exit early. Such changes are ignored by the
  ** session module. */
  rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
  if( rc!=SQLITE_OK ) goto error_out;

1161
1162
1163
1164
1165
1166
1167



1168
1169
1170
1171
1172
1173
1174
        pC->bIndirect = 0;
      }
    }
  }

  /* If an error has occurred, mark the session object as failed. */
 error_out:



  if( rc!=SQLITE_OK ){
    pSession->rc = rc;
  }
}

static int sessionFindTable(
  sqlite3_session *pSession, 







>
>
>







1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
        pC->bIndirect = 0;
      }
    }
  }

  /* If an error has occurred, mark the session object as failed. */
 error_out:
  if( pTab->bStat1 ){
    pSession->hook = stat1.hook;
  }
  if( rc!=SQLITE_OK ){
    pSession->rc = rc;
  }
}

static int sessionFindTable(
  sqlite3_session *pSession, 
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
          int i;
          for(i=0; i<nCol; i++){
            if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
            if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
            if( abPK[i] ) bHasPk = 1;
          }
        }

      }
      sqlite3_free((char*)azCol);
      if( bMismatch ){
        *pzErrMsg = sqlite3_mprintf("table schemas do not match");
        rc = SQLITE_SCHEMA;
      }
      if( bHasPk==0 ){







<







1578
1579
1580
1581
1582
1583
1584

1585
1586
1587
1588
1589
1590
1591
          int i;
          for(i=0; i<nCol; i++){
            if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
            if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
            if( abPK[i] ) bHasPk = 1;
          }
        }

      }
      sqlite3_free((char*)azCol);
      if( bMismatch ){
        *pzErrMsg = sqlite3_mprintf("table schemas do not match");
        rc = SQLITE_SCHEMA;
      }
      if( bHasPk==0 ){
1623
1624
1625
1626
1627
1628
1629

1630
1631
1632
1633
1634
1635
1636
    if( (*pp)==pSession ){
      *pp = (*pp)->pNext;
      if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
      break;
    }
  }
  sqlite3_mutex_leave(sqlite3_db_mutex(db));


  /* Delete all attached table objects. And the contents of their 
  ** associated hash-tables. */
  sessionDeleteTable(pSession->pTable);

  /* Free the session object itself. */
  sqlite3_free(pSession);







>







1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
    if( (*pp)==pSession ){
      *pp = (*pp)->pNext;
      if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
      break;
    }
  }
  sqlite3_mutex_leave(sqlite3_db_mutex(db));
  sqlite3ValueFree(pSession->pZeroBlob);

  /* Delete all attached table objects. And the contents of their 
  ** associated hash-tables. */
  sessionDeleteTable(pSession->pTable);

  /* Free the session object itself. */
  sqlite3_free(pSession);
2090
2091
2092
2093
2094
2095
2096









2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114




2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
  const char *zTab,               /* Table name */
  int nCol,                       /* Number of columns in table */
  const char **azCol,             /* Names of table columns */
  u8 *abPK,                       /* PRIMARY KEY  array */
  sqlite3_stmt **ppStmt           /* OUT: Prepared SELECT statement */
){
  int rc = SQLITE_OK;









  int i;
  const char *zSep = "";
  SessionBuffer buf = {0, 0, 0};

  sessionAppendStr(&buf, "SELECT * FROM ", &rc);
  sessionAppendIdent(&buf, zDb, &rc);
  sessionAppendStr(&buf, ".", &rc);
  sessionAppendIdent(&buf, zTab, &rc);
  sessionAppendStr(&buf, " WHERE ", &rc);
  for(i=0; i<nCol; i++){
    if( abPK[i] ){
      sessionAppendStr(&buf, zSep, &rc);
      sessionAppendIdent(&buf, azCol[i], &rc);
      sessionAppendStr(&buf, " = ?", &rc);
      sessionAppendInteger(&buf, i+1, &rc);
      zSep = " AND ";
    }
  }




  if( rc==SQLITE_OK ){
    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0);
  }
  sqlite3_free(buf.aBuf);
  return rc;
}

/*
** Bind the PRIMARY KEY values from the change passed in argument pChange
** to the SELECT statement passed as the first argument. The SELECT statement
** is as prepared by function sessionSelectStmt().







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

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

|

|







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
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
  const char *zTab,               /* Table name */
  int nCol,                       /* Number of columns in table */
  const char **azCol,             /* Names of table columns */
  u8 *abPK,                       /* PRIMARY KEY  array */
  sqlite3_stmt **ppStmt           /* OUT: Prepared SELECT statement */
){
  int rc = SQLITE_OK;
  char *zSql = 0;
  int nSql = -1;

  if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
    zSql = sqlite3_mprintf(
        "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
        "idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
    );
  }else{
    int i;
    const char *zSep = "";
    SessionBuffer buf = {0, 0, 0};

    sessionAppendStr(&buf, "SELECT * FROM ", &rc);
    sessionAppendIdent(&buf, zDb, &rc);
    sessionAppendStr(&buf, ".", &rc);
    sessionAppendIdent(&buf, zTab, &rc);
    sessionAppendStr(&buf, " WHERE ", &rc);
    for(i=0; i<nCol; i++){
      if( abPK[i] ){
        sessionAppendStr(&buf, zSep, &rc);
        sessionAppendIdent(&buf, azCol[i], &rc);
        sessionAppendStr(&buf, " IS ?", &rc);
        sessionAppendInteger(&buf, i+1, &rc);
        zSep = " AND ";
      }
    }
    zSql = (char*)buf.aBuf;
    nSql = buf.nBuf;
  }

  if( rc==SQLITE_OK ){
    rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
  }
  sqlite3_free(zSql);
  return rc;
}

/*
** Bind the PRIMARY KEY values from the change passed in argument pChange
** to the SELECT statement passed as the first argument. The SELECT statement
** is as prepared by function sessionSelectStmt().
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
  sqlite3_stmt *pDelete;          /* DELETE statement */
  sqlite3_stmt *pUpdate;          /* UPDATE statement */
  sqlite3_stmt *pInsert;          /* INSERT statement */
  sqlite3_stmt *pSelect;          /* SELECT statement */
  int nCol;                       /* Size of azCol[] and abPK[] arrays */
  const char **azCol;             /* Array of column names */
  u8 *abPK;                       /* Boolean array - true if column is in PK */

  int bDeferConstraints;          /* True to defer constraints */
  SessionBuffer constraints;      /* Deferred constraints are stored here */
};

/*
** Formulate a statement to DELETE a row from database db. Assuming a table
** structure like this:







|







3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
  sqlite3_stmt *pDelete;          /* DELETE statement */
  sqlite3_stmt *pUpdate;          /* UPDATE statement */
  sqlite3_stmt *pInsert;          /* INSERT statement */
  sqlite3_stmt *pSelect;          /* SELECT statement */
  int nCol;                       /* Size of azCol[] and abPK[] arrays */
  const char **azCol;             /* Array of column names */
  u8 *abPK;                       /* Boolean array - true if column is in PK */
  int bStat1;                     /* True if table is sqlite_stat1 */
  int bDeferConstraints;          /* True to defer constraints */
  SessionBuffer constraints;      /* Deferred constraints are stored here */
};

/*
** Formulate a statement to DELETE a row from database db. Assuming a table
** structure like this:
3449
3450
3451
3452
3453
3454
3455

3456
3457
3458
3459
3460
3461
3462
  if( rc==SQLITE_OK ){
    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
  }
  sqlite3_free(buf.aBuf);

  return rc;
}


/*
** Formulate and prepare an SQL statement to query table zTab by primary
** key. Assuming the following table structure:
**
**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
**







>







3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
  if( rc==SQLITE_OK ){
    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
  }
  sqlite3_free(buf.aBuf);

  return rc;
}


/*
** Formulate and prepare an SQL statement to query table zTab by primary
** key. Assuming the following table structure:
**
**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
**
3510
3511
3512
3513
3514
3515
3516









































3517
3518
3519
3520
3521
3522
3523

  if( rc==SQLITE_OK ){
    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
  }
  sqlite3_free(buf.aBuf);
  return rc;
}










































/*
** A wrapper around sqlite3_bind_value() that detects an extra problem. 
** See comments in the body of this function for details.
*/
static int sessionBindValue(
  sqlite3_stmt *pStmt,            /* Statement to bind value to */







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







3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659

  if( rc==SQLITE_OK ){
    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
  }
  sqlite3_free(buf.aBuf);
  return rc;
}

static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
  return sqlite3_prepare_v2(db, zSql, -1, pp, 0);
}

/*
** Prepare statements for applying changes to the sqlite_stat1 table.
** These are similar to those created by sessionSelectRow(),
** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for 
** other tables.
*/
static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
  int rc = sessionSelectRow(db, "sqlite_stat1", p);
  if( rc==SQLITE_OK ){
    rc = sessionPrepare(db, &p->pInsert,
        "INSERT INTO main.sqlite_stat1 VALUES(?1, "
        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
        "?3)"
    );
  }
  if( rc==SQLITE_OK ){
    rc = sessionPrepare(db, &p->pUpdate,
        "UPDATE main.sqlite_stat1 SET "
        "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
        "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
        "stat = CASE WHEN ?8 THEN ?9 ELSE stat END  "
        "WHERE tbl=?1 AND idx IS "
        "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
        "AND (?10 OR ?8=0 OR stat IS ?7)"
    );
  }
  if( rc==SQLITE_OK ){
    rc = sessionPrepare(db, &p->pDelete,
        "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
        "AND (?4 OR stat IS ?3)"
    );
  }
  assert( rc==SQLITE_OK );
  return rc;
}

/*
** A wrapper around sqlite3_bind_value() that detects an extra problem. 
** See comments in the body of this function for details.
*/
static int sessionBindValue(
  sqlite3_stmt *pStmt,            /* Statement to bind value to */
3841
3842
3843
3844
3845
3846
3847












3848
3849
3850
3851
3852


3853
3854
3855
3856
3857
3858
3859
      rc = sessionConflictHandler(
          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
      );
    }

  }else{
    assert( op==SQLITE_INSERT );












    rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
    if( rc!=SQLITE_OK ) return rc;

    sqlite3_step(p->pInsert);
    rc = sqlite3_reset(p->pInsert);


    if( (rc&0xff)==SQLITE_CONSTRAINT ){
      rc = sessionConflictHandler(
          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
      );
    }
  }








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

|
|
>
>







3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
      rc = sessionConflictHandler(
          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
      );
    }

  }else{
    assert( op==SQLITE_INSERT );
    if( p->bStat1 ){
      /* Check if there is a conflicting row. For sqlite_stat1, this needs
      ** to be done using a SELECT, as there is no PRIMARY KEY in the 
      ** database schema to throw an exception if a duplicate is inserted.  */
      rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
      if( rc==SQLITE_ROW ){
        rc = SQLITE_CONSTRAINT;
        sqlite3_reset(p->pSelect);
      }
    }

    if( rc==SQLITE_OK ){
      rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
      if( rc!=SQLITE_OK ) return rc;

      sqlite3_step(p->pInsert);
      rc = sqlite3_reset(p->pInsert);
    }

    if( (rc&0xff)==SQLITE_CONSTRAINT ){
      rc = sessionConflictHandler(
          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
      );
    }
  }

4078
4079
4080
4081
4082
4083
4084






4085
4086
4087
4088
4089
4090


4091
4092
4093
4094
4095
4096
4097
          schemaMismatch = 1;
          sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
              "primary key mismatch for table %s", zTab
          );
        }
        else{
          sApply.nCol = nCol;






          if((rc = sessionSelectRow(db, zTab, &sApply))
          || (rc = sessionUpdateRow(db, zTab, &sApply))
          || (rc = sessionDeleteRow(db, zTab, &sApply))
          || (rc = sessionInsertRow(db, zTab, &sApply))
          ){
            break;


          }
        }
        nTab = sqlite3Strlen30(zTab);
      }
    }

    /* If there is a schema mismatch on the current table, proceed to the







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







4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
          schemaMismatch = 1;
          sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
              "primary key mismatch for table %s", zTab
          );
        }
        else{
          sApply.nCol = nCol;
          if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
            if( (rc = sessionStat1Sql(db, &sApply) ) ){
              break;
            }
            sApply.bStat1 = 1;
          }else{
            if((rc = sessionSelectRow(db, zTab, &sApply))
                || (rc = sessionUpdateRow(db, zTab, &sApply))
                || (rc = sessionDeleteRow(db, zTab, &sApply))
                || (rc = sessionInsertRow(db, zTab, &sApply))
              ){
              break;
            }
            sApply.bStat1 = 0;
          }
        }
        nTab = sqlite3Strlen30(zTab);
      }
    }

    /* If there is a schema mismatch on the current table, proceed to the
Changes to ext/session/sqlite3session.h.
143
144
145
146
147
148
149





























150
151
152
153
154
155
156
** no changes will be recorded in either of these scenarios.
**
** Changes are not recorded for individual rows that have NULL values stored
** in one or more of their PRIMARY KEY columns.
**
** SQLITE_OK is returned if the call completes without error. Or, if an error 
** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.





























*/
int sqlite3session_attach(
  sqlite3_session *pSession,      /* Session object */
  const char *zTab                /* Table name */
);

/*







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







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
** no changes will be recorded in either of these scenarios.
**
** Changes are not recorded for individual rows that have NULL values stored
** in one or more of their PRIMARY KEY columns.
**
** SQLITE_OK is returned if the call completes without error. Or, if an error 
** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
**
** <h3>Special sqlite_stat1 Handling</h3>
**
** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to 
** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
**  <pre>
**  &nbsp;     CREATE TABLE sqlite_stat1(tbl,idx,stat)  
**  </pre>
**
** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are 
** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes 
** are recorded for rows for which (idx IS NULL) is true. However, for such
** rows a zero-length blob (SQL value X'') is stored in the changeset or
** patchset instead of a NULL value. This allows such changesets to be
** manipulated by legacy implementations of sqlite3changeset_invert(),
** concat() and similar.
**
** The sqlite3changeset_apply() function automatically converts the 
** zero-length blob back to a NULL value when updating the sqlite_stat1
** table. However, if the application calls sqlite3changeset_new(),
** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset 
** iterator directly (including on a changeset iterator passed to a
** conflict-handler callback) then the X'' value is returned. The application
** must translate X'' to NULL itself if required.
**
** Legacy (older than 3.22.0) versions of the sessions module cannot capture
** changes made to the sqlite_stat1 table. Legacy versions of the
** sqlite3changeset_apply() function silently ignore any modifications to the
** sqlite_stat1 table that are part of a changeset or patchset.
*/
int sqlite3session_attach(
  sqlite3_session *pSession,      /* Session object */
  const char *zTab                /* Table name */
);

/*
Changes to main.mk.
367
368
369
370
371
372
373

374
375
376
377
378
379
380
381
382
383
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c \
  $(TOP)/ext/misc/vfslog.c \

  $(TOP)/ext/fts5/fts5_tcl.c \
  $(TOP)/ext/fts5/fts5_test_mi.c \
  $(TOP)/ext/fts5/fts5_test_tok.c 


#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

TESTSRC2 = \
  $(TOP)/src/attach.c \







>


|







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  $(TOP)/ext/misc/remember.c \
  $(TOP)/ext/misc/series.c \
  $(TOP)/ext/misc/spellfix.c \
  $(TOP)/ext/misc/totype.c \
  $(TOP)/ext/misc/unionvtab.c \
  $(TOP)/ext/misc/wholenumber.c \
  $(TOP)/ext/misc/vfslog.c \
  $(TOP)/ext/misc/zipfile.c \
  $(TOP)/ext/fts5/fts5_tcl.c \
  $(TOP)/ext/fts5/fts5_test_mi.c \
  $(TOP)/ext/fts5/fts5_test_tok.c


#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

TESTSRC2 = \
  $(TOP)/src/attach.c \
418
419
420
421
422
423
424

425
426
427
428
429
430
431
  parse.c \
  $(TOP)/ext/fts3/fts3.c \
  $(TOP)/ext/fts3/fts3_aux.c \
  $(TOP)/ext/fts3/fts3_expr.c \
  $(TOP)/ext/fts3/fts3_tokenizer.c \
  $(TOP)/ext/fts3/fts3_write.c \
  $(TOP)/ext/async/sqlite3async.c \

  $(TOP)/ext/session/sqlite3session.c \
  $(TOP)/ext/session/test_session.c 

# Header files used by all library source files.
#
HDR = \
   $(TOP)/src/btree.h \







>







419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  parse.c \
  $(TOP)/ext/fts3/fts3.c \
  $(TOP)/ext/fts3/fts3_aux.c \
  $(TOP)/ext/fts3/fts3_expr.c \
  $(TOP)/ext/fts3/fts3_tokenizer.c \
  $(TOP)/ext/fts3/fts3_write.c \
  $(TOP)/ext/async/sqlite3async.c \
  $(TOP)/ext/misc/stmt.c \
  $(TOP)/ext/session/sqlite3session.c \
  $(TOP)/ext/session/test_session.c 

# Header files used by all library source files.
#
HDR = \
   $(TOP)/src/btree.h \
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
#
TESTPROGS = \
  testfixture$(EXE) \
  sqlite3$(EXE) \
  sqlite3_analyzer$(EXE) \
  sqlite3_checker$(EXE) \
  sqldiff$(EXE) \
  dbhash$(EXE)


# Databases containing fuzzer test cases
#
FUZZDATA = \
  $(TOP)/test/fuzzdata1.db \
  $(TOP)/test/fuzzdata2.db \
  $(TOP)/test/fuzzdata3.db \
  $(TOP)/test/fuzzdata4.db \
  $(TOP)/test/fuzzdata5.db

# Standard options to testfixture
#
TESTOPTS = --verbose=file --output=test-out.txt

# Extra compiler options for various shell tools
#
SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5

SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS







|
>

















>







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
#
TESTPROGS = \
  testfixture$(EXE) \
  sqlite3$(EXE) \
  sqlite3_analyzer$(EXE) \
  sqlite3_checker$(EXE) \
  sqldiff$(EXE) \
  dbhash$(EXE) \
  sqltclsh$(EXE)

# Databases containing fuzzer test cases
#
FUZZDATA = \
  $(TOP)/test/fuzzdata1.db \
  $(TOP)/test/fuzzdata2.db \
  $(TOP)/test/fuzzdata3.db \
  $(TOP)/test/fuzzdata4.db \
  $(TOP)/test/fuzzdata5.db

# Standard options to testfixture
#
TESTOPTS = --verbose=file --output=test-out.txt

# Extra compiler options for various shell tools
#
SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
SHELL_OPT += -DSQLITE_ENABLE_RTREE
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS
689
690
691
692
693
694
695

696
697
698

699
700


701
702
703
704
705
706
707
keywordhash.h:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash >keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \

	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c \

	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h



shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
	tclsh $(TOP)/tool/mkshellc.tcl >shell.c



# Rules to build the extension objects.







>



>

|
>
>







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
keywordhash.h:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash >keywordhash.h

# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c \
	$(TOP)/ext/misc/sqlar.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
        $(TOP)/src/test_windirent.c

shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
	tclsh $(TOP)/tool/mkshellc.tcl >shell.c



# Rules to build the extension objects.
811
812
813
814
815
816
817






818
819
820
821
822
823
824
		$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)

sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/sqlite3_analyzer.c.in $(TOP)/tool/mkccode.tcl
	tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c

sqlite3_analyzer$(EXE): sqlite3_analyzer.c
	$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB) 







sqlite3_expert$(EXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
	$(TCCX) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert$(EXE) $(THREADLIB)

CHECKER_DEPS =\
  $(TOP)/tool/mkccode.tcl \
  sqlite3.c \







>
>
>
>
>
>







819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
		$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)

sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/sqlite3_analyzer.c.in $(TOP)/tool/mkccode.tcl
	tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c

sqlite3_analyzer$(EXE): sqlite3_analyzer.c
	$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB) 

sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl
	tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c

sqltclsh$(EXE): sqltclsh.c
	$(TCCX) $(TCL_FLAGS) sqltclsh.c -o $@ $(LIBTCL) $(THREADLIB) 

sqlite3_expert$(EXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
	$(TCCX) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert$(EXE) $(THREADLIB)

CHECKER_DEPS =\
  $(TOP)/tool/mkccode.tcl \
  sqlite3.c \
Changes to src/analyze.c.
230
231
232
233
234
235
236




237
238
239
240
241
242
243
      aCreateTbl[i] = 0;
      sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
      if( zWhere ){
        sqlite3NestedParse(pParse,
           "DELETE FROM %Q.%s WHERE %s=%Q",
           pDb->zDbSName, zTab, zWhereType, zWhere
        );




      }else{
        /* The sqlite_stat[134] table already exists.  Delete all rows. */
        sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
      }
    }
  }








>
>
>
>







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
      aCreateTbl[i] = 0;
      sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
      if( zWhere ){
        sqlite3NestedParse(pParse,
           "DELETE FROM %Q.%s WHERE %s=%Q",
           pDb->zDbSName, zTab, zWhereType, zWhere
        );
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
      }else if( db->xPreUpdateCallback ){
        sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
#endif
      }else{
        /* The sqlite_stat[134] table already exists.  Delete all rows. */
        sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
      }
    }
  }

994
995
996
997
998
999
1000



1001
1002
1003
1004
1005
1006
1007
  int regRowid = iMem++;       /* Rowid argument passed to stat_push() */
#endif
  int regTemp = iMem++;        /* Temporary use register */
  int regTabname = iMem++;     /* Register containing table name */
  int regIdxname = iMem++;     /* Register containing index name */
  int regStat1 = iMem++;       /* Value for the stat column of sqlite_stat1 */
  int regPrev = iMem;          /* MUST BE LAST (see below) */




  pParse->nMem = MAX(pParse->nMem, iMem);
  v = sqlite3GetVdbe(pParse);
  if( v==0 || NEVER(pTab==0) ){
    return;
  }
  if( pTab->tnum==0 ){







>
>
>







998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  int regRowid = iMem++;       /* Rowid argument passed to stat_push() */
#endif
  int regTemp = iMem++;        /* Temporary use register */
  int regTabname = iMem++;     /* Register containing table name */
  int regIdxname = iMem++;     /* Register containing index name */
  int regStat1 = iMem++;       /* Value for the stat column of sqlite_stat1 */
  int regPrev = iMem;          /* MUST BE LAST (see below) */
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  Table *pStat1 = 0; 
#endif

  pParse->nMem = MAX(pParse->nMem, iMem);
  v = sqlite3GetVdbe(pParse);
  if( v==0 || NEVER(pTab==0) ){
    return;
  }
  if( pTab->tnum==0 ){
1018
1019
1020
1021
1022
1023
1024












1025
1026
1027
1028
1029
1030
1031
  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
#ifndef SQLITE_OMIT_AUTHORIZATION
  if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
      db->aDb[iDb].zDbSName ) ){
    return;
  }
#endif













  /* Establish a read-lock on the table at the shared-cache level. 
  ** Open a read-only cursor on the table. Also allocate a cursor number
  ** to use for scanning indexes (iIdxCur). No index cursor is opened at
  ** this time though.  */
  sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
  iTabCur = iTab++;







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







1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
#ifndef SQLITE_OMIT_AUTHORIZATION
  if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
      db->aDb[iDb].zDbSName ) ){
    return;
  }
#endif

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  if( db->xPreUpdateCallback ){
    pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
    if( pStat1==0 ) return;
    pStat1->zName = (char*)&pStat1[1];
    memcpy(pStat1->zName, "sqlite_stat1", 13);
    pStat1->nCol = 3;
    pStat1->iPKey = -1;
    sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
  }
#endif

  /* Establish a read-lock on the table at the shared-cache level. 
  ** Open a read-only cursor on the table. Also allocate a cursor number
  ** to use for scanning indexes (iIdxCur). No index cursor is opened at
  ** this time though.  */
  sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
  iTabCur = iTab++;
1220
1221
1222
1223
1224
1225
1226



1227
1228
1229
1230
1231
1232
1233

    /* Add the entry to the stat1 table. */
    callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
    assert( "BBB"[0]==SQLITE_AFF_TEXT );
    sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);



    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);

    /* Add the entries to the stat3 or stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    {
      int regEq = regStat1;
      int regLt = regStat1+1;







>
>
>







1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255

    /* Add the entry to the stat1 table. */
    callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
    assert( "BBB"[0]==SQLITE_AFF_TEXT );
    sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
#endif
    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);

    /* Add the entries to the stat3 or stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    {
      int regEq = regStat1;
      int regLt = regStat1+1;
1283
1284
1285
1286
1287
1288
1289



1290
1291
1292
1293
1294
1295
1296
    jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v);
    sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
    assert( "BBB"[0]==SQLITE_AFF_TEXT );
    sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);



    sqlite3VdbeJumpHere(v, jZeroRows);
  }
}


/*
** Generate code that will cause the most recent index analysis to







>
>
>







1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
    jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v);
    sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
    assert( "BBB"[0]==SQLITE_AFF_TEXT );
    sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
#endif
    sqlite3VdbeJumpHere(v, jZeroRows);
  }
}


/*
** Generate code that will cause the most recent index analysis to
Changes to src/btree.c.
119
120
121
122
123
124
125


126
127
128

129
130
131
132
133
134
135
** If SQLITE_DEBUG is not defined, then this macro is equivalent to
** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message
** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented
** with the page number and filename associated with the (MemPage*).
*/
#ifdef SQLITE_DEBUG
int corruptPageError(int lineno, MemPage *p){


  char *zMsg = sqlite3_mprintf("database corruption page %d of %s",
      (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
  );

  if( zMsg ){
    sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
  }
  sqlite3_free(zMsg);
  return SQLITE_CORRUPT_BKPT;
}
# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)







>
>
|


>







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
** If SQLITE_DEBUG is not defined, then this macro is equivalent to
** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message
** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented
** with the page number and filename associated with the (MemPage*).
*/
#ifdef SQLITE_DEBUG
int corruptPageError(int lineno, MemPage *p){
  char *zMsg;
  sqlite3BeginBenignMalloc();
  zMsg = sqlite3_mprintf("database corruption page %d of %s",
      (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
  );
  sqlite3EndBenignMalloc();
  if( zMsg ){
    sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
  }
  sqlite3_free(zMsg);
  return SQLITE_CORRUPT_BKPT;
}
# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
static void freePage(MemPage *pPage, int *pRC){
  if( (*pRC)==SQLITE_OK ){
    *pRC = freePage2(pPage->pBt, pPage, pPage->pgno);
  }
}

/*
** Free any overflow pages associated with the given Cell.  Write the
** local Cell size (the number of bytes on the original page, omitting
** overflow) into *pnSize.
*/
static int clearCell(
  MemPage *pPage,          /* The page that contains the Cell */
  unsigned char *pCell,    /* First byte of the Cell */
  CellInfo *pInfo          /* Size information about the cell */
){
  BtShared *pBt;







|
|
<







6185
6186
6187
6188
6189
6190
6191
6192
6193

6194
6195
6196
6197
6198
6199
6200
static void freePage(MemPage *pPage, int *pRC){
  if( (*pRC)==SQLITE_OK ){
    *pRC = freePage2(pPage->pBt, pPage, pPage->pgno);
  }
}

/*
** Free any overflow pages associated with the given Cell.  Store
** size information about the cell in pInfo.

*/
static int clearCell(
  MemPage *pPage,          /* The page that contains the Cell */
  unsigned char *pCell,    /* First byte of the Cell */
  CellInfo *pInfo          /* Size information about the cell */
){
  BtShared *pBt;
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
    */
    if( pOld->aData[0]!=apOld[0]->aData[0] ){
      rc = SQLITE_CORRUPT_BKPT;
      goto balance_cleanup;
    }

    /* Load b.apCell[] with pointers to all cells in pOld.  If pOld
    ** constains overflow cells, include them in the b.apCell[] array
    ** in the correct spot.
    **
    ** Note that when there are multiple overflow cells, it is always the
    ** case that they are sequential and adjacent.  This invariant arises
    ** because multiple overflows can only occurs when inserting divider
    ** cells into a parent on a prior balance, and divider cells are always
    ** adjacent and are inserted in order.  There is an assert() tagged







|







7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
    */
    if( pOld->aData[0]!=apOld[0]->aData[0] ){
      rc = SQLITE_CORRUPT_BKPT;
      goto balance_cleanup;
    }

    /* Load b.apCell[] with pointers to all cells in pOld.  If pOld
    ** contains overflow cells, include them in the b.apCell[] array
    ** in the correct spot.
    **
    ** Note that when there are multiple overflow cells, it is always the
    ** case that they are sequential and adjacent.  This invariant arises
    ** because multiple overflows can only occurs when inserting divider
    ** cells into a parent on a prior balance, and divider cells are always
    ** adjacent and are inserted in order.  There is an assert() tagged
Changes to src/btreeInt.h.
562
563
564
565
566
567
568
569
570

571
572
573
574
575
576
577
** CURSOR_FAULT:
**   An unrecoverable error (an I/O error or a malloc failure) has occurred
**   on a different connection that shares the BtShared cache with this
**   cursor.  The error has left the cache in an inconsistent state.
**   Do nothing else with this cursor.  Any attempt to use the cursor
**   should return the error code stored in BtCursor.skipNext
*/
#define CURSOR_INVALID           0
#define CURSOR_VALID             1

#define CURSOR_SKIPNEXT          2
#define CURSOR_REQUIRESEEK       3
#define CURSOR_FAULT             4

/* 
** The database page the PENDING_BYTE occupies. This page is never used.
*/







<
|
>







562
563
564
565
566
567
568

569
570
571
572
573
574
575
576
577
** CURSOR_FAULT:
**   An unrecoverable error (an I/O error or a malloc failure) has occurred
**   on a different connection that shares the BtShared cache with this
**   cursor.  The error has left the cache in an inconsistent state.
**   Do nothing else with this cursor.  Any attempt to use the cursor
**   should return the error code stored in BtCursor.skipNext
*/

#define CURSOR_VALID             0
#define CURSOR_INVALID           1
#define CURSOR_SKIPNEXT          2
#define CURSOR_REQUIRESEEK       3
#define CURSOR_FAULT             4

/* 
** The database page the PENDING_BYTE occupies. This page is never used.
*/
Changes to src/build.c.
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
  p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
  if( db->mallocFailed ) goto create_view_fail;

  /* Locate the end of the CREATE VIEW statement.  Make sEnd point to
  ** the end.
  */
  sEnd = pParse->sLastToken;
  assert( sEnd.z[0]!=0 );
  if( sEnd.z[0]!=';' ){
    sEnd.z += sEnd.n;
  }
  sEnd.n = 0;
  n = (int)(sEnd.z - pBegin->z);
  assert( n>0 );
  z = pBegin->z;







|







2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
  p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
  if( db->mallocFailed ) goto create_view_fail;

  /* Locate the end of the CREATE VIEW statement.  Make sEnd point to
  ** the end.
  */
  sEnd = pParse->sLastToken;
  assert( sEnd.z[0]!=0 || sEnd.n==0 );
  if( sEnd.z[0]!=';' ){
    sEnd.z += sEnd.n;
  }
  sEnd.n = 0;
  n = (int)(sEnd.z - pBegin->z);
  assert( n>0 );
  z = pBegin->z;
Changes to src/delete.c.
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  ** the update-hook is not invoked for rows removed by REPLACE, but the 
  ** pre-update-hook is.
  */ 
  if( pTab->pSelect==0 ){
    u8 p5 = 0;
    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
    sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
    if( pParse->nested==0 ){
      sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
    }
    if( eMode!=ONEPASS_OFF ){
      sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
    }
    if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){
      sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);







|







756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  ** the update-hook is not invoked for rows removed by REPLACE, but the 
  ** pre-update-hook is.
  */ 
  if( pTab->pSelect==0 ){
    u8 p5 = 0;
    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
    sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
    if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
      sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
    }
    if( eMode!=ONEPASS_OFF ){
      sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
    }
    if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){
      sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
Changes to src/expr.c.
654
655
656
657
658
659
660
661
662

663
664
665
666
667
668
669
670
671
672
673
674
675
676
  if( p ){
    int i;
    for(i=0; i<p->nExpr; i++){
      heightOfExpr(p->a[i].pExpr, pnHeight);
    }
  }
}
static void heightOfSelect(Select *p, int *pnHeight){
  if( p ){

    heightOfExpr(p->pWhere, pnHeight);
    heightOfExpr(p->pHaving, pnHeight);
    heightOfExpr(p->pLimit, pnHeight);
    heightOfExprList(p->pEList, pnHeight);
    heightOfExprList(p->pGroupBy, pnHeight);
    heightOfExprList(p->pOrderBy, pnHeight);
    heightOfSelect(p->pPrior, pnHeight);
  }
}

/*
** Set the Expr.nHeight variable in the structure passed as an 
** argument. An expression with no children, Expr.pList or 
** Expr.pSelect member has a height of 1. Any other expression







|
|
>






<







654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669

670
671
672
673
674
675
676
  if( p ){
    int i;
    for(i=0; i<p->nExpr; i++){
      heightOfExpr(p->a[i].pExpr, pnHeight);
    }
  }
}
static void heightOfSelect(Select *pSelect, int *pnHeight){
  Select *p;
  for(p=pSelect; p; p=p->pPrior){
    heightOfExpr(p->pWhere, pnHeight);
    heightOfExpr(p->pHaving, pnHeight);
    heightOfExpr(p->pLimit, pnHeight);
    heightOfExprList(p->pEList, pnHeight);
    heightOfExprList(p->pGroupBy, pnHeight);
    heightOfExprList(p->pOrderBy, pnHeight);

  }
}

/*
** Set the Expr.nHeight variable in the structure passed as an 
** argument. An expression with no children, Expr.pList or 
** Expr.pSelect member has a height of 1. Any other expression
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
      if( pSel->pLimit ){
        sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft);
        pSel->pLimit->pLeft = pLimit;
      }else{
        pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
      }
      pSel->iLimit = 0;
      pSel->selFlags &= ~SF_MultiValue;
      if( sqlite3Select(pParse, pSel, &dest) ){
        return 0;
      }
      rReg = dest.iSDParm;
      ExprSetVVAProperty(pExpr, EP_NoReduce);
      break;
    }







<







2760
2761
2762
2763
2764
2765
2766

2767
2768
2769
2770
2771
2772
2773
      if( pSel->pLimit ){
        sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft);
        pSel->pLimit->pLeft = pLimit;
      }else{
        pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
      }
      pSel->iLimit = 0;

      if( sqlite3Select(pParse, pSel, &dest) ){
        return 0;
      }
      rReg = dest.iSDParm;
      ExprSetVVAProperty(pExpr, EP_NoReduce);
      break;
    }
Changes to src/func.c.
31
32
33
34
35
36
37


38
39
40
41
42
43
44
}

/*
** Indicate that the accumulator load should be skipped on this
** iteration of the aggregate loop.
*/
static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){


  context->skipFlag = 1;
}

/*
** Implementation of the non-aggregate min() and max() functions
*/
static void minmaxFunc(







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
}

/*
** Indicate that the accumulator load should be skipped on this
** iteration of the aggregate loop.
*/
static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){
  assert( context->isError<=0 );
  context->isError = -1;
  context->skipFlag = 1;
}

/*
** Implementation of the non-aggregate min() and max() functions
*/
static void minmaxFunc(
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
** Implementation of the length() function
*/
static void lengthFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int len;

  assert( argc==1 );
  UNUSED_PARAMETER(argc);
  switch( sqlite3_value_type(argv[0]) ){
    case SQLITE_BLOB:
    case SQLITE_INTEGER:
    case SQLITE_FLOAT: {
      sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
      break;
    }
    case SQLITE_TEXT: {
      const unsigned char *z = sqlite3_value_text(argv[0]);


      if( z==0 ) return;
      len = 0;
      while( *z ){
        len++;
        SQLITE_SKIP_UTF8(z);


      }

      sqlite3_result_int(context, len);
      break;
    }
    default: {
      sqlite3_result_null(context);
      break;
    }
  }







<
<











>
>

|
|
|
<
>
>
|
>
|







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
** Implementation of the length() function
*/
static void lengthFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){


  assert( argc==1 );
  UNUSED_PARAMETER(argc);
  switch( sqlite3_value_type(argv[0]) ){
    case SQLITE_BLOB:
    case SQLITE_INTEGER:
    case SQLITE_FLOAT: {
      sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
      break;
    }
    case SQLITE_TEXT: {
      const unsigned char *z = sqlite3_value_text(argv[0]);
      const unsigned char *z0;
      unsigned char c;
      if( z==0 ) return;
      z0 = z;
      while( (c = *z)!=0 ){
        z++;

        if( c>=0xc0 ){
          while( (*z & 0xc0)==0x80 ){ z++; z0++; }
        }
      }
      sqlite3_result_int(context, (int)(z-z0));
      break;
    }
    default: {
      sqlite3_result_null(context);
      break;
    }
  }
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
    FUNCTION2(unlikely,          1, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
    FUNCTION2(likelihood,        2, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
    FUNCTION2(likely,            1, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
#ifdef SQLITE_DEBUG
    FUNCTION2(affinity,          1, 0, 0, noopFunc,  SQLITE_FUNC_AFFINITY),
#endif
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    FUNCTION2(sqlite_unsupported_offset,
                                 1, 0, 0, noopFunc,  SQLITE_FUNC_OFFSET|
                                                     SQLITE_FUNC_TYPEOF),
#endif
    FUNCTION(ltrim,              1, 1, 0, trimFunc         ),
    FUNCTION(ltrim,              2, 1, 0, trimFunc         ),
    FUNCTION(rtrim,              1, 2, 0, trimFunc         ),
    FUNCTION(rtrim,              2, 2, 0, trimFunc         ),
    FUNCTION(trim,               1, 3, 0, trimFunc         ),







<
|







1800
1801
1802
1803
1804
1805
1806

1807
1808
1809
1810
1811
1812
1813
1814
    FUNCTION2(unlikely,          1, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
    FUNCTION2(likelihood,        2, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
    FUNCTION2(likely,            1, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
#ifdef SQLITE_DEBUG
    FUNCTION2(affinity,          1, 0, 0, noopFunc,  SQLITE_FUNC_AFFINITY),
#endif
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC

    FUNCTION2(sqlite_offset,     1, 0, 0, noopFunc,  SQLITE_FUNC_OFFSET|
                                                     SQLITE_FUNC_TYPEOF),
#endif
    FUNCTION(ltrim,              1, 1, 0, trimFunc         ),
    FUNCTION(ltrim,              2, 1, 0, trimFunc         ),
    FUNCTION(rtrim,              1, 2, 0, trimFunc         ),
    FUNCTION(rtrim,              2, 2, 0, trimFunc         ),
    FUNCTION(trim,               1, 3, 0, trimFunc         ),
Changes to src/loadext.c.
426
427
428
429
430
431
432
433




434
435
436
437
438
439
440
  /* Version 3.18.0 and later */
  sqlite3_set_last_insert_rowid,
  /* Version 3.20.0 and later */
  sqlite3_prepare_v3,
  sqlite3_prepare16_v3,
  sqlite3_bind_pointer,
  sqlite3_result_pointer,
  sqlite3_value_pointer




};

/*
** Attempt to load an SQLite extension library contained in the file
** zFile.  The entry point is zProc.  zProc may be 0 in which case a
** default entry point name (sqlite3_extension_init) is used.  Use
** of the default name is recommended.







|
>
>
>
>







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  /* Version 3.18.0 and later */
  sqlite3_set_last_insert_rowid,
  /* Version 3.20.0 and later */
  sqlite3_prepare_v3,
  sqlite3_prepare16_v3,
  sqlite3_bind_pointer,
  sqlite3_result_pointer,
  sqlite3_value_pointer,
  /* Version 3.22.0 and later */
  sqlite3_vtab_nochange,
  sqlite3_value_nochange,
  sqlite3_vtab_collation
};

/*
** Attempt to load an SQLite extension library contained in the file
** zFile.  The entry point is zProc.  zProc may be 0 in which case a
** default entry point name (sqlite3_extension_init) is used.  Use
** of the default name is recommended.
Changes to src/main.c.
1319
1320
1321
1322
1323
1324
1325

1326
1327
1328
1329
1330
1331
1332
      case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
      case SQLITE_NOMEM:              zName = "SQLITE_NOMEM";             break;
      case SQLITE_READONLY:           zName = "SQLITE_READONLY";          break;
      case SQLITE_READONLY_RECOVERY:  zName = "SQLITE_READONLY_RECOVERY"; break;
      case SQLITE_READONLY_CANTINIT:  zName = "SQLITE_READONLY_CANTINIT"; break;
      case SQLITE_READONLY_ROLLBACK:  zName = "SQLITE_READONLY_ROLLBACK"; break;
      case SQLITE_READONLY_DBMOVED:   zName = "SQLITE_READONLY_DBMOVED";  break;

      case SQLITE_INTERRUPT:          zName = "SQLITE_INTERRUPT";         break;
      case SQLITE_IOERR:              zName = "SQLITE_IOERR";             break;
      case SQLITE_IOERR_READ:         zName = "SQLITE_IOERR_READ";        break;
      case SQLITE_IOERR_SHORT_READ:   zName = "SQLITE_IOERR_SHORT_READ";  break;
      case SQLITE_IOERR_WRITE:        zName = "SQLITE_IOERR_WRITE";       break;
      case SQLITE_IOERR_FSYNC:        zName = "SQLITE_IOERR_FSYNC";       break;
      case SQLITE_IOERR_DIR_FSYNC:    zName = "SQLITE_IOERR_DIR_FSYNC";   break;







>







1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
      case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
      case SQLITE_NOMEM:              zName = "SQLITE_NOMEM";             break;
      case SQLITE_READONLY:           zName = "SQLITE_READONLY";          break;
      case SQLITE_READONLY_RECOVERY:  zName = "SQLITE_READONLY_RECOVERY"; break;
      case SQLITE_READONLY_CANTINIT:  zName = "SQLITE_READONLY_CANTINIT"; break;
      case SQLITE_READONLY_ROLLBACK:  zName = "SQLITE_READONLY_ROLLBACK"; break;
      case SQLITE_READONLY_DBMOVED:   zName = "SQLITE_READONLY_DBMOVED";  break;
      case SQLITE_READONLY_DIRECTORY: zName = "SQLITE_READONLY_DIRECTORY";break;
      case SQLITE_INTERRUPT:          zName = "SQLITE_INTERRUPT";         break;
      case SQLITE_IOERR:              zName = "SQLITE_IOERR";             break;
      case SQLITE_IOERR_READ:         zName = "SQLITE_IOERR_READ";        break;
      case SQLITE_IOERR_SHORT_READ:   zName = "SQLITE_IOERR_SHORT_READ";  break;
      case SQLITE_IOERR_WRITE:        zName = "SQLITE_IOERR_WRITE";       break;
      case SQLITE_IOERR_FSYNC:        zName = "SQLITE_IOERR_FSYNC";       break;
      case SQLITE_IOERR_DIR_FSYNC:    zName = "SQLITE_IOERR_DIR_FSYNC";   break;
Changes to src/malloc.c.
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
** SQL statement.  Make a copy of this phrase in space obtained form
** sqlite3DbMalloc().  Omit leading and trailing whitespace.
*/
char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
  int n;
  while( sqlite3Isspace(zStart[0]) ) zStart++;
  n = (int)(zEnd - zStart);
  while( n>0 && sqlite3Isspace(zStart[n-1]) ) n--;
  return sqlite3DbStrNDup(db, zStart, n);
}

/*
** Free any prior content in *pz and replace it with a copy of zNew.
*/
void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){







|







632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
** SQL statement.  Make a copy of this phrase in space obtained form
** sqlite3DbMalloc().  Omit leading and trailing whitespace.
*/
char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
  int n;
  while( sqlite3Isspace(zStart[0]) ) zStart++;
  n = (int)(zEnd - zStart);
  while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--;
  return sqlite3DbStrNDup(db, zStart, n);
}

/*
** Free any prior content in *pz and replace it with a copy of zNew.
*/
void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
Changes to src/os_unix.c.
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
  if( pFile->sectorSize == 0 ){
    struct statvfs fsInfo;
       
    /* Set defaults for non-supported filesystems */
    pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    pFile->deviceCharacteristics = 0;
    if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
      return pFile->sectorSize;
    }

    if( !strcmp(fsInfo.f_basetype, "tmp") ) {
      pFile->sectorSize = fsInfo.f_bsize;
      pFile->deviceCharacteristics =
        SQLITE_IOCAP_ATOMIC4K |       /* All ram filesystem writes are atomic */
        SQLITE_IOCAP_SAFE_APPEND |    /* growing the file does not occur until







|







3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
  if( pFile->sectorSize == 0 ){
    struct statvfs fsInfo;
       
    /* Set defaults for non-supported filesystems */
    pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    pFile->deviceCharacteristics = 0;
    if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
      return;
    }

    if( !strcmp(fsInfo.f_basetype, "tmp") ) {
      pFile->sectorSize = fsInfo.f_bsize;
      pFile->deviceCharacteristics =
        SQLITE_IOCAP_ATOMIC4K |       /* All ram filesystem writes are atomic */
        SQLITE_IOCAP_SAFE_APPEND |    /* growing the file does not occur until
5900
5901
5902
5903
5904
5905
5906





5907
5908
5909
5910
5911
5912
5913
5914
5915

5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
      assert( !p->pPreallocatedUnused );
      assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
      return rc;
    }
    fd = robust_open(zName, openFlags, openMode);
    OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
    assert( !isExclusive || (openFlags & O_CREAT)!=0 );





    if( fd<0 && errno!=EISDIR && isReadWrite ){
      /* Failed to open the file for read/write access. Try read-only. */
      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
      openFlags &= ~(O_RDWR|O_CREAT);
      flags |= SQLITE_OPEN_READONLY;
      openFlags |= O_RDONLY;
      isReadonly = 1;
      fd = robust_open(zName, openFlags, openMode);
    }

    if( fd<0 ){
      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
      /* If unable to create a journal, change the error code to
      ** indicate that the directory permissions are wrong. */
      if( isNewJrnl && osAccess(zName, F_OK) ) rc = SQLITE_READONLY_DIRECTORY;
      goto open_finished;
    }

    /* If this process is running as root and if creating a new rollback
    ** journal or WAL file, set the ownership of the journal or WAL to be
    ** the same as the original database.
    */







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

|
<
<
|







5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923


5924
5925
5926
5927
5928
5929
5930
5931
      assert( !p->pPreallocatedUnused );
      assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
      return rc;
    }
    fd = robust_open(zName, openFlags, openMode);
    OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
    assert( !isExclusive || (openFlags & O_CREAT)!=0 );
    if( fd<0 ){
      if( isNewJrnl && errno==EACCES && osAccess(zName, F_OK) ){
        /* If unable to create a journal because the directory is not
        ** writable, change the error code to indicate that. */
        rc = SQLITE_READONLY_DIRECTORY;
      }else if( errno!=EISDIR && isReadWrite ){
        /* Failed to open the file for read/write access. Try read-only. */
        flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
        openFlags &= ~(O_RDWR|O_CREAT);
        flags |= SQLITE_OPEN_READONLY;
        openFlags |= O_RDONLY;
        isReadonly = 1;
        fd = robust_open(zName, openFlags, openMode);
      }
    }
    if( fd<0 ){
      int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);


      if( rc==SQLITE_OK ) rc = rc2;
      goto open_finished;
    }

    /* If this process is running as root and if creating a new rollback
    ** journal or WAL file, set the ownership of the journal or WAL to be
    ** the same as the original database.
    */
Changes to src/os_win.c.
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
** file are currently open, in this process or in other processes, then
** the file must be truncated to zero length or have its header cleared.
*/
static int winOpenSharedMemory(winFile *pDbFd){
  struct winShm *p;                  /* The connection to be opened */
  winShmNode *pShmNode = 0;          /* The underlying mmapped file */
  int rc = SQLITE_OK;                /* Result code */
  int rc2 = SQLITE_ERROR;            /* winOpen result code */
  winShmNode *pNew;                  /* Newly allocated winShmNode */
  int nName;                         /* Size of zName in bytes */

  assert( pDbFd->pShm==0 );    /* Not previously opened */

  /* Allocate space for the new sqlite3_shm object.  Also speculatively
  ** allocate space for a new winShmNode and filename.







<







3861
3862
3863
3864
3865
3866
3867

3868
3869
3870
3871
3872
3873
3874
** file are currently open, in this process or in other processes, then
** the file must be truncated to zero length or have its header cleared.
*/
static int winOpenSharedMemory(winFile *pDbFd){
  struct winShm *p;                  /* The connection to be opened */
  winShmNode *pShmNode = 0;          /* The underlying mmapped file */
  int rc = SQLITE_OK;                /* Result code */

  winShmNode *pNew;                  /* Newly allocated winShmNode */
  int nName;                         /* Size of zName in bytes */

  assert( pDbFd->pShm==0 );    /* Not previously opened */

  /* Allocate space for the new sqlite3_shm object.  Also speculatively
  ** allocate space for a new winShmNode and filename.
3895
3896
3897
3898
3899
3900
3901



3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
    ** use FILE_ID_BOTH_DIR_INFO Structure.
    */
    if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
  }
  if( pShmNode ){
    sqlite3_free(pNew);
  }else{



    pShmNode = pNew;
    pNew = 0;
    ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
    pShmNode->pNext = winShmNodeList;
    winShmNodeList = pShmNode;

    if( sqlite3GlobalConfig.bCoreMutex ){
      pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
      if( pShmNode->mutex==0 ){
        rc = SQLITE_IOERR_NOMEM_BKPT;
        goto shm_open_err;
      }
    }

    if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
      rc2 = winOpen(pDbFd->pVfs,
                    pShmNode->zFilename,
                    (sqlite3_file*)&pShmNode->hFile,
                    SQLITE_OPEN_WAL|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,
                    0);
    }
    if( rc2!=SQLITE_OK ){
      rc2 = winOpen(pDbFd->pVfs,
                    pShmNode->zFilename,
                    (sqlite3_file*)&pShmNode->hFile,
                    SQLITE_OPEN_WAL|SQLITE_OPEN_READONLY,
                    0);
      if( rc2!=SQLITE_OK ){
        rc = winLogError(rc2, osGetLastError(), "winOpenShm",
                         pShmNode->zFilename);
        goto shm_open_err;
      }
      pShmNode->isReadonly = 1;
    }

    rc = winLockSharedMemory(pShmNode);
    if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
  }

  /* Make the new connection a child of the winShmNode */
  p->pShmNode = pShmNode;







>
>
>















|
|
<
|
<

<
|
<
|
<
|
|
|
|
|
|
|
<







3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920

3921

3922

3923

3924

3925
3926
3927
3928
3929
3930
3931

3932
3933
3934
3935
3936
3937
3938
    ** use FILE_ID_BOTH_DIR_INFO Structure.
    */
    if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
  }
  if( pShmNode ){
    sqlite3_free(pNew);
  }else{
    int inFlags = SQLITE_OPEN_WAL;
    int outFlags = 0;

    pShmNode = pNew;
    pNew = 0;
    ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
    pShmNode->pNext = winShmNodeList;
    winShmNodeList = pShmNode;

    if( sqlite3GlobalConfig.bCoreMutex ){
      pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
      if( pShmNode->mutex==0 ){
        rc = SQLITE_IOERR_NOMEM_BKPT;
        goto shm_open_err;
      }
    }

    if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
      inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    }else{

      inFlags |= SQLITE_OPEN_READONLY;

    }

    rc = winOpen(pDbFd->pVfs, pShmNode->zFilename,

                 (sqlite3_file*)&pShmNode->hFile,

                 inFlags, &outFlags);
    if( rc!=SQLITE_OK ){
      rc = winLogError(rc, osGetLastError(), "winOpenShm",
                       pShmNode->zFilename);
      goto shm_open_err;
    }
    if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;


    rc = winLockSharedMemory(pShmNode);
    if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
  }

  /* Make the new connection a child of the winShmNode */
  p->pShmNode = pShmNode;
5114
5115
5116
5117
5118
5119
5120
5121

5122

5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136

5137

5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154

5155

5156
5157
5158
5159
5160
5161
5162
      h = osCreateFile2((LPCWSTR)zConverted,
                        dwDesiredAccess,
                        dwShareMode,
                        dwCreationDisposition,
                        &extendedParameters);
      if( h!=INVALID_HANDLE_VALUE ) break;
      if( isReadWrite ){
        int isRO = 0;

        int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);

        if( rc2==SQLITE_OK && isRO ) break;
      }
    }while( winRetryIoerr(&cnt, &lastErrno) );
#else
    do{
      h = osCreateFileW((LPCWSTR)zConverted,
                        dwDesiredAccess,
                        dwShareMode, NULL,
                        dwCreationDisposition,
                        dwFlagsAndAttributes,
                        NULL);
      if( h!=INVALID_HANDLE_VALUE ) break;
      if( isReadWrite ){
        int isRO = 0;

        int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);

        if( rc2==SQLITE_OK && isRO ) break;
      }
    }while( winRetryIoerr(&cnt, &lastErrno) );
#endif
  }
#ifdef SQLITE_WIN32_HAS_ANSI
  else{
    do{
      h = osCreateFileA((LPCSTR)zConverted,
                        dwDesiredAccess,
                        dwShareMode, NULL,
                        dwCreationDisposition,
                        dwFlagsAndAttributes,
                        NULL);
      if( h!=INVALID_HANDLE_VALUE ) break;
      if( isReadWrite ){
        int isRO = 0;

        int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);

        if( rc2==SQLITE_OK && isRO ) break;
      }
    }while( winRetryIoerr(&cnt, &lastErrno) );
  }
#endif
  winLogIoerr(cnt, __LINE__);








|
>
|
>













|
>
|
>
















|
>
|
>







5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
      h = osCreateFile2((LPCWSTR)zConverted,
                        dwDesiredAccess,
                        dwShareMode,
                        dwCreationDisposition,
                        &extendedParameters);
      if( h!=INVALID_HANDLE_VALUE ) break;
      if( isReadWrite ){
        int rc2, isRO = 0;
        sqlite3BeginBenignMalloc();
        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
        sqlite3EndBenignMalloc();
        if( rc2==SQLITE_OK && isRO ) break;
      }
    }while( winRetryIoerr(&cnt, &lastErrno) );
#else
    do{
      h = osCreateFileW((LPCWSTR)zConverted,
                        dwDesiredAccess,
                        dwShareMode, NULL,
                        dwCreationDisposition,
                        dwFlagsAndAttributes,
                        NULL);
      if( h!=INVALID_HANDLE_VALUE ) break;
      if( isReadWrite ){
        int rc2, isRO = 0;
        sqlite3BeginBenignMalloc();
        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
        sqlite3EndBenignMalloc();
        if( rc2==SQLITE_OK && isRO ) break;
      }
    }while( winRetryIoerr(&cnt, &lastErrno) );
#endif
  }
#ifdef SQLITE_WIN32_HAS_ANSI
  else{
    do{
      h = osCreateFileA((LPCSTR)zConverted,
                        dwDesiredAccess,
                        dwShareMode, NULL,
                        dwCreationDisposition,
                        dwFlagsAndAttributes,
                        NULL);
      if( h!=INVALID_HANDLE_VALUE ) break;
      if( isReadWrite ){
        int rc2, isRO = 0;
        sqlite3BeginBenignMalloc();
        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
        sqlite3EndBenignMalloc();
        if( rc2==SQLITE_OK && isRO ) break;
      }
    }while( winRetryIoerr(&cnt, &lastErrno) );
  }
#endif
  winLogIoerr(cnt, __LINE__);

Changes to src/pager.c.
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
  assert( isOpen(pPager->fd) );
  dc = sqlite3OsDeviceCharacteristics(pPager->fd);
#else
  UNUSED_PARAMETER(pPager);
#endif

#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
  if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
    return -1;
  }
#endif

#ifdef SQLITE_ENABLE_ATOMIC_WRITE
  {
    int nSector = pPager->sectorSize;







|







1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
  assert( isOpen(pPager->fd) );
  dc = sqlite3OsDeviceCharacteristics(pPager->fd);
#else
  UNUSED_PARAMETER(pPager);
#endif

#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
  if( pPager->dbSize>0 && (dc&SQLITE_IOCAP_BATCH_ATOMIC) ){
    return -1;
  }
#endif

#ifdef SQLITE_ENABLE_ATOMIC_WRITE
  {
    int nSector = pPager->sectorSize;
6497
6498
6499
6500
6501
6502
6503
6504


6505
6506
6507
6508
6509
6510
6511
6512
        rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
      }
      rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
      if( bBatch ){
        if( rc==SQLITE_OK ){
          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
        }else{


          sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
        }
      }

      if( rc!=SQLITE_OK ){
        assert( rc!=SQLITE_IOERR_BLOCKED );
        goto commit_phase_one_exit;
      }







<
>
>
|







6497
6498
6499
6500
6501
6502
6503

6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
        rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
      }
      rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
      if( bBatch ){
        if( rc==SQLITE_OK ){
          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);

        }
        if( rc!=SQLITE_OK ){
          sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
        }
      }

      if( rc!=SQLITE_OK ){
        assert( rc!=SQLITE_IOERR_BLOCKED );
        goto commit_phase_one_exit;
      }
Changes to src/parse.y.
27
28
29
30
31
32
33
34
35



36
37
38
39
40
41
42
// The generated parser function takes a 4th argument as follows:
%extra_argument {Parse *pParse}

// This code runs whenever there is a syntax error
//
%syntax_error {
  UNUSED_PARAMETER(yymajor);  /* Silence some compiler warnings */
  assert( TOKEN.z[0] );  /* The tokenizer always gives us a token */
  sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);



}
%stack_overflow {
  sqlite3ErrorMsg(pParse, "parser stack overflow");
}

// The name of the generated procedure that implements the parser
// is as follows:







|
|
>
>
>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// The generated parser function takes a 4th argument as follows:
%extra_argument {Parse *pParse}

// This code runs whenever there is a syntax error
//
%syntax_error {
  UNUSED_PARAMETER(yymajor);  /* Silence some compiler warnings */
  if( TOKEN.z[0] ){
    sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
  }else{
    sqlite3ErrorMsg(pParse, "incomplete input");
  }
}
%stack_overflow {
  sqlite3ErrorMsg(pParse, "parser stack overflow");
}

// The name of the generated procedure that implements the parser
// is as follows:
Changes to src/select.c.
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
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
/*
** Handle the special case of a compound-select that originates from a
** VALUES clause.  By handling this as a special case, we avoid deep
** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
** on a VALUES clause.
**
** Because the Select object originates from a VALUES clause:
**   (1) It has no LIMIT or OFFSET
**   (2) All terms are UNION ALL
**   (3) There is no ORDER BY clause





*/
static int multiSelectValues(
  Parse *pParse,        /* Parsing context */
  Select *p,            /* The right-most of SELECTs to be coded */
  SelectDest *pDest     /* What to do with query results */
){
  Select *pPrior;

  int nRow = 1;
  int rc = 0;
  assert( p->selFlags & SF_MultiValue );
  do{
    assert( p->selFlags & SF_Values );
    assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
    assert( p->pLimit==0 );
    assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
    if( p->pPrior==0 ) break;
    assert( p->pPrior->pNext==p );
    p = p->pPrior;
    nRow++;
  }while(1);
  while( p ){
    pPrior = p->pPrior;
    p->pPrior = 0;
    rc = sqlite3Select(pParse, p, pDest);
    p->pPrior = pPrior;
    if( rc ) break;
    p->nSelectRow = nRow;
    p = p->pNext;
  }
  return rc;
}

/*







|


>
>
>
>
>







>






<











|







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
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
/*
** Handle the special case of a compound-select that originates from a
** VALUES clause.  By handling this as a special case, we avoid deep
** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
** on a VALUES clause.
**
** Because the Select object originates from a VALUES clause:
**   (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1
**   (2) All terms are UNION ALL
**   (3) There is no ORDER BY clause
**
** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES
** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))").
** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case.
** Since the limit is exactly 1, we only need to evalutes the left-most VALUES.
*/
static int multiSelectValues(
  Parse *pParse,        /* Parsing context */
  Select *p,            /* The right-most of SELECTs to be coded */
  SelectDest *pDest     /* What to do with query results */
){
  Select *pPrior;
  Select *pRightmost = p;
  int nRow = 1;
  int rc = 0;
  assert( p->selFlags & SF_MultiValue );
  do{
    assert( p->selFlags & SF_Values );
    assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );

    assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
    if( p->pPrior==0 ) break;
    assert( p->pPrior->pNext==p );
    p = p->pPrior;
    nRow++;
  }while(1);
  while( p ){
    pPrior = p->pPrior;
    p->pPrior = 0;
    rc = sqlite3Select(pParse, p, pDest);
    p->pPrior = pPrior;
    if( rc || pRightmost->pLimit ) break;
    p->nSelectRow = nRow;
    p = p->pNext;
  }
  return rc;
}

/*
Changes to src/shell.c.in.
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
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"



#if SQLITE_USER_AUTHENTICATION
# include "sqlite3userauth.h"
#endif
#include <ctype.h>
#include <stdarg.h>

#if !defined(_WIN32) && !defined(WIN32)
# include <signal.h>
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
#  include <pwd.h>
# endif


# include <unistd.h>
# include <sys/types.h>






#endif



#if HAVE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif

#if HAVE_EDITLINE







>
>
>











>
>

|
>
>
>
>
>
>

>
>







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
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
typedef unsigned char u8;
#if SQLITE_USER_AUTHENTICATION
# include "sqlite3userauth.h"
#endif
#include <ctype.h>
#include <stdarg.h>

#if !defined(_WIN32) && !defined(WIN32)
# include <signal.h>
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
#  include <pwd.h>
# endif
#endif
#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
# include <unistd.h>
# include <dirent.h>
# if defined(__MINGW32__)
#  define DIRENT dirent
#  ifndef S_ISLNK
#   define S_ISLNK(mode) (0)
#  endif
# endif
#endif
#include <sys/types.h>
#include <sys/stat.h>

#if HAVE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif

#if HAVE_EDITLINE
335
336
337
338
339
340
341





342
343
344
345
346
347
348
#endif

/*
** Used to prevent warnings about unused parameters
*/
#define UNUSED_PARAMETER(x) (void)(x)






/*
** If the following flag is set, then command execution stops
** at an error if we are not interactive.
*/
static int bail_on_error = 0;

/*







>
>
>
>
>







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
#endif

/*
** Used to prevent warnings about unused parameters
*/
#define UNUSED_PARAMETER(x) (void)(x)

/*
** Number of elements in an array
*/
#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))

/*
** If the following flag is set, then command execution stops
** at an error if we are not interactive.
*/
static int bail_on_error = 0;

/*
607
608
609
610
611
612
613



























































614
615
616
617
618
619
620
    free(zPrior);
    zResult = shell_readline(zPrompt);
    if( zResult && *zResult ) shell_add_history(zResult);
#endif
  }
  return zResult;
}



























































/*
** A variable length string to which one can append text.
*/
typedef struct ShellText ShellText;
struct ShellText {
  char *z;
  int n;







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







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
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
    free(zPrior);
    zResult = shell_readline(zPrompt);
    if( zResult && *zResult ) shell_add_history(zResult);
#endif
  }
  return zResult;
}


/*
** Return the value of a hexadecimal digit.  Return -1 if the input
** is not a hex digit.
*/
static int hexDigitValue(char c){
  if( c>='0' && c<='9' ) return c - '0';
  if( c>='a' && c<='f' ) return c - 'a' + 10;
  if( c>='A' && c<='F' ) return c - 'A' + 10;
  return -1;
}

/*
** Interpret zArg as an integer value, possibly with suffixes.
*/
static sqlite3_int64 integerValue(const char *zArg){
  sqlite3_int64 v = 0;
  static const struct { char *zSuffix; int iMult; } aMult[] = {
    { "KiB", 1024 },
    { "MiB", 1024*1024 },
    { "GiB", 1024*1024*1024 },
    { "KB",  1000 },
    { "MB",  1000000 },
    { "GB",  1000000000 },
    { "K",   1000 },
    { "M",   1000000 },
    { "G",   1000000000 },
  };
  int i;
  int isNeg = 0;
  if( zArg[0]=='-' ){
    isNeg = 1;
    zArg++;
  }else if( zArg[0]=='+' ){
    zArg++;
  }
  if( zArg[0]=='0' && zArg[1]=='x' ){
    int x;
    zArg += 2;
    while( (x = hexDigitValue(zArg[0]))>=0 ){
      v = (v<<4) + x;
      zArg++;
    }
  }else{
    while( IsDigit(zArg[0]) ){
      v = v*10 + zArg[0] - '0';
      zArg++;
    }
  }
  for(i=0; i<ArraySize(aMult); i++){
    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
      v *= aMult[i].iMult;
      break;
    }
  }
  return isNeg? -v : v;
}

/*
** A variable length string to which one can append text.
*/
typedef struct ShellText ShellText;
struct ShellText {
  char *z;
  int n;
784
785
786
787
788
789
790

791
792
793

794
795
796
797
798
799
800
static void shellModuleSchema(
  sqlite3_context *pCtx,
  int nVal,
  sqlite3_value **apVal
){
  const char *zName = (const char*)sqlite3_value_text(apVal[0]);
  char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);

  if( zFake ){
    sqlite3_result_text(pCtx, sqlite3_mprintf("/* %z */", zFake),
                        -1, sqlite3_free);

  }
}

/*
** SQL function:  shell_add_schema(S,X)
**
** Add the schema name X to the CREATE statement in S and return the result.







>

|

>







861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
static void shellModuleSchema(
  sqlite3_context *pCtx,
  int nVal,
  sqlite3_value **apVal
){
  const char *zName = (const char*)sqlite3_value_text(apVal[0]);
  char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);
  UNUSED_PARAMETER(nVal);
  if( zFake ){
    sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
                        -1, sqlite3_free);
    free(zFake);
  }
}

/*
** SQL function:  shell_add_schema(S,X)
**
** Add the schema name X to the CREATE statement in S and return the result.
827
828
829
830
831
832
833

834
835
836
837
838
839
840
841
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
868
869
870
871
872
873
874
875
876





877
878
879





880
881
882
883
884
885
886
     "VIRTUAL TABLE"
  };
  int i = 0;
  const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
  const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
  const char *zName = (const char*)sqlite3_value_text(apVal[2]);
  sqlite3 *db = sqlite3_context_db_handle(pCtx);

  if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
    for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
      int n = strlen30(aPrefix[i]);
      if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
        char *z = 0;
        char *zFake = 0;
        if( zSchema ){
          char cQuote = quoteChar(zSchema);
          if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
            z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
          }else{
            z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
          }
        }
        if( zName
         && aPrefix[i][0]=='V'
         && (zFake = shellFakeSchema(db, zSchema, zName))!=0
        ){
          if( z==0 ){
            z = sqlite3_mprintf("%s\n/* %z */", zIn, zFake);
          }else{
            z = sqlite3_mprintf("%z\n/* %z */", z, zFake);
          }

        }
        if( z ){
          sqlite3_result_text(pCtx, z, -1, sqlite3_free);
          return;
        }
      }
    }
  }
  sqlite3_result_value(pCtx, apVal[0]);
}

/*
** The source code for several run-time loadable extensions is inserted
** below by the ../tool/mkshellc.tcl script.  Before processing that included
** code, we need to override some macros to make the included program code
** work here in the middle of this regular program.
*/
#define SQLITE_EXTENSION_INIT1
#define SQLITE_EXTENSION_INIT2(X) (void)(X)






INCLUDE ../ext/misc/shathree.c
INCLUDE ../ext/misc/fileio.c
INCLUDE ../ext/misc/completion.c





INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c

#if defined(SQLITE_ENABLE_SESSION)
/*
** State information for a single open session
*/







>



















|

|

>




















>
>
>
>
>



>
>
>
>
>







906
907
908
909
910
911
912
913
914
915
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
977
     "VIRTUAL TABLE"
  };
  int i = 0;
  const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
  const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
  const char *zName = (const char*)sqlite3_value_text(apVal[2]);
  sqlite3 *db = sqlite3_context_db_handle(pCtx);
  UNUSED_PARAMETER(nVal);
  if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
    for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
      int n = strlen30(aPrefix[i]);
      if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
        char *z = 0;
        char *zFake = 0;
        if( zSchema ){
          char cQuote = quoteChar(zSchema);
          if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
            z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
          }else{
            z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
          }
        }
        if( zName
         && aPrefix[i][0]=='V'
         && (zFake = shellFakeSchema(db, zSchema, zName))!=0
        ){
          if( z==0 ){
            z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
          }else{
            z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
          }
          free(zFake);
        }
        if( z ){
          sqlite3_result_text(pCtx, z, -1, sqlite3_free);
          return;
        }
      }
    }
  }
  sqlite3_result_value(pCtx, apVal[0]);
}

/*
** The source code for several run-time loadable extensions is inserted
** below by the ../tool/mkshellc.tcl script.  Before processing that included
** code, we need to override some macros to make the included program code
** work here in the middle of this regular program.
*/
#define SQLITE_EXTENSION_INIT1
#define SQLITE_EXTENSION_INIT2(X) (void)(X)

#if defined(_WIN32) && defined(_MSC_VER)
INCLUDE test_windirent.h
INCLUDE test_windirent.c
#define dirent DIRENT
#endif
INCLUDE ../ext/misc/shathree.c
INCLUDE ../ext/misc/fileio.c
INCLUDE ../ext/misc/completion.c
INCLUDE ../ext/misc/appendvfs.c
#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
#endif
INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c

#if defined(SQLITE_ENABLE_SESSION)
/*
** State information for a single open session
*/
914
915
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
/*
** State information about the database connection is contained in an
** instance of the following structure.
*/
typedef struct ShellState ShellState;
struct ShellState {
  sqlite3 *db;           /* The database */
  int autoExplain;       /* Automatically turn on .explain mode */
  int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
  int statsOn;           /* True to display memory stats before each finalize */
  int scanstatsOn;       /* True to display scan stats before each finalize */


  int outCount;          /* Revert to stdout when reaching zero */
  int cnt;               /* Number of records displayed so far */
  FILE *out;             /* Write results here */
  FILE *traceOut;        /* Output for sqlite3_trace() */
  int nErr;              /* Number of errors seen */
  int mode;              /* An output mode setting */

  int cMode;             /* temporary output mode for the current query */
  int normalMode;        /* Output mode before ".explain on" */
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  int nCheck;            /* Number of ".check" commands run */
  unsigned shellFlgs;    /* Various flags */
  char *zDestTable;      /* Name of destination table when MODE_Insert */

  char zTestcase[30];    /* Name of current test case */
  char colSeparator[20]; /* Column separator character for several modes */
  char rowSeparator[20]; /* Row separator character for MODE_Ascii */


  int colWidth[100];     /* Requested width of each column when in column mode*/
  int actualWidth[100];  /* Actual width of each column */
  char nullValue[20];    /* The text to print when a NULL comes back from
                         ** the database */
  char outfile[FILENAME_MAX]; /* Filename for *out */
  const char *zDbFilename;    /* name of the database file */
  char *zFreeOnClose;         /* Filename to free when closing */
  const char *zVfs;           /* Name of VFS to use */
  sqlite3_stmt *pStmt;   /* Current statement if any. */
  FILE *pLog;            /* Write log output here */
  int *aiIndent;         /* Array of indents used in MODE_Explain */
  int nIndent;           /* Size of array aiIndent[] */
  int iIndent;           /* Index of current op in aiIndent[] */
#if defined(SQLITE_ENABLE_SESSION)
  int nSession;             /* Number of active sessions */
  OpenSession aSession[4];  /* Array of sessions.  [0] is in focus. */
#endif
  ExpertInfo expert;        /* Valid if previous command was ".expert OPT..." */
};


/* Allowed values for ShellState.autoEQP
*/
#define AUTOEQP_off      0
#define AUTOEQP_on       1
#define AUTOEQP_trigger  2
#define AUTOEQP_full     3








/*
** These are the allowed shellFlgs values
*/
#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */







|
|
|
|
>
>






>







>



>
>



















>








>
>
>
>
>
>
>







1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
/*
** State information about the database connection is contained in an
** instance of the following structure.
*/
typedef struct ShellState ShellState;
struct ShellState {
  sqlite3 *db;           /* The database */
  u8 autoExplain;        /* Automatically turn on .explain mode */
  u8 autoEQP;            /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
  u8 statsOn;            /* True to display memory stats before each finalize */
  u8 scanstatsOn;        /* True to display scan stats before each finalize */
  u8 openMode;           /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
  u8 doXdgOpen;          /* Invoke start/open/xdg-open in output_reset() */
  int outCount;          /* Revert to stdout when reaching zero */
  int cnt;               /* Number of records displayed so far */
  FILE *out;             /* Write results here */
  FILE *traceOut;        /* Output for sqlite3_trace() */
  int nErr;              /* Number of errors seen */
  int mode;              /* An output mode setting */
  int modePrior;         /* Saved mode */
  int cMode;             /* temporary output mode for the current query */
  int normalMode;        /* Output mode before ".explain on" */
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  int nCheck;            /* Number of ".check" commands run */
  unsigned shellFlgs;    /* Various flags */
  char *zDestTable;      /* Name of destination table when MODE_Insert */
  char *zTempFile;       /* Temporary file that might need deleting */
  char zTestcase[30];    /* Name of current test case */
  char colSeparator[20]; /* Column separator character for several modes */
  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
  char colSepPrior[20];  /* Saved column separator */
  char rowSepPrior[20];  /* Saved row separator */
  int colWidth[100];     /* Requested width of each column when in column mode*/
  int actualWidth[100];  /* Actual width of each column */
  char nullValue[20];    /* The text to print when a NULL comes back from
                         ** the database */
  char outfile[FILENAME_MAX]; /* Filename for *out */
  const char *zDbFilename;    /* name of the database file */
  char *zFreeOnClose;         /* Filename to free when closing */
  const char *zVfs;           /* Name of VFS to use */
  sqlite3_stmt *pStmt;   /* Current statement if any. */
  FILE *pLog;            /* Write log output here */
  int *aiIndent;         /* Array of indents used in MODE_Explain */
  int nIndent;           /* Size of array aiIndent[] */
  int iIndent;           /* Index of current op in aiIndent[] */
#if defined(SQLITE_ENABLE_SESSION)
  int nSession;             /* Number of active sessions */
  OpenSession aSession[4];  /* Array of sessions.  [0] is in focus. */
#endif
  ExpertInfo expert;        /* Valid if previous command was ".expert OPT..." */
};


/* Allowed values for ShellState.autoEQP
*/
#define AUTOEQP_off      0
#define AUTOEQP_on       1
#define AUTOEQP_trigger  2
#define AUTOEQP_full     3

/* Allowed values for ShellState.openMode
*/
#define SHELL_OPEN_UNSPEC     0      /* No open-mode specified */
#define SHELL_OPEN_NORMAL     1      /* Normal database file */
#define SHELL_OPEN_APPENDVFS  2      /* Use appendvfs */
#define SHELL_OPEN_ZIPFILE    3      /* Use the zipfile virtual table */

/*
** These are the allowed shellFlgs values
*/
#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043






























































































































































1044
1045
1046
1047
1048
1049
1050
#define SEP_Tab       "\t"
#define SEP_Space     " "
#define SEP_Comma     ","
#define SEP_CrLf      "\r\n"
#define SEP_Unit      "\x1F"
#define SEP_Record    "\x1E"

/*
** Number of elements in an array
*/
#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))

/*
** A callback for the sqlite3_log() interface.
*/
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
  ShellState *p = (ShellState*)pArg;
  if( p->pLog==0 ) return;
  utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
  fflush(p->pLog);
}































































































































































/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
  int i;
  char *zBlob = (char *)pBlob;







<
<
<
<
<









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







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
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
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
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
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
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
#define SEP_Tab       "\t"
#define SEP_Space     " "
#define SEP_Comma     ","
#define SEP_CrLf      "\r\n"
#define SEP_Unit      "\x1F"
#define SEP_Record    "\x1E"






/*
** A callback for the sqlite3_log() interface.
*/
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
  ShellState *p = (ShellState*)pArg;
  if( p->pLog==0 ) return;
  utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
  fflush(p->pLog);
}

/*
** SQL function:  shell_putsnl(X)
**
** Write the text X to the screen (or whatever output is being directed)
** adding a newline at the end, and then return X.
*/
static void shellPutsFunc(
  sqlite3_context *pCtx,
  int nVal,
  sqlite3_value **apVal
){
  ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
  (void)nVal;
  utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
  sqlite3_result_value(pCtx, apVal[0]);
}

/*
** SQL function:   edit(VALUE)
**                 edit(VALUE,EDITOR)
**
** These steps:
**
**     (1) Write VALUE into a temporary file.
**     (2) Run program EDITOR on that temporary file.
**     (3) Read the temporary file back and return its content as the result.
**     (4) Delete the temporary file
**
** If the EDITOR argument is omitted, use the value in the VISUAL
** environment variable.  If still there is no EDITOR, through an error.
**
** Also throw an error if the EDITOR program returns a non-zero exit code.
*/
static void editFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zEditor;
  char *zTempFile = 0;
  sqlite3 *db;
  char *zCmd = 0;
  int bBin;
  int rc;
  FILE *f = 0;
  sqlite3_int64 sz;
  sqlite3_int64 x;
  unsigned char *p = 0;

  if( argc==2 ){
    zEditor = (const char*)sqlite3_value_text(argv[1]);
  }else{
    zEditor = getenv("VISUAL");
  }
  if( zEditor==0 ){
    sqlite3_result_error(context, "no editor for edit()", -1);
    return;
  }
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
    sqlite3_result_error(context, "NULL input to edit()", -1);
    return;
  }
  db = sqlite3_context_db_handle(context);
  zTempFile = 0;
  sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile);
  if( zTempFile==0 ){
    sqlite3_uint64 r = 0;
    sqlite3_randomness(sizeof(r), &r);
    zTempFile = sqlite3_mprintf("temp%llx", r);
    if( zTempFile==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
  }
  bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
  f = fopen(zTempFile, bBin ? "wb" : "w");
  if( f==0 ){
    sqlite3_result_error(context, "edit() cannot open temp file", -1);
    goto edit_func_end;
  }
  sz = sqlite3_value_bytes(argv[0]);
  if( bBin ){
    x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f);
  }else{
    x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f);
  }
  fclose(f);
  f = 0;
  if( x!=sz ){
    sqlite3_result_error(context, "edit() could not write the whole file", -1);
    goto edit_func_end;
  }
  zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile);
  if( zCmd==0 ){
    sqlite3_result_error_nomem(context);
    goto edit_func_end;
  }
  rc = system(zCmd);
  sqlite3_free(zCmd);
  if( rc ){
    sqlite3_result_error(context, "EDITOR returned non-zero", -1);
    goto edit_func_end;
  }
  f = fopen(zTempFile, bBin ? "rb" : "r");
  if( f==0 ){
    sqlite3_result_error(context,
      "edit() cannot reopen temp file after edit", -1);
    goto edit_func_end;
  }
  fseek(f, 0, SEEK_END);
  sz = ftell(f);
  rewind(f);
  p = sqlite3_malloc64( sz+(bBin==0) );
  if( p==0 ){
    sqlite3_result_error_nomem(context);
    goto edit_func_end;
  }
  if( bBin ){
    x = fread(p, 1, sz, f);
  }else{
    x = fread(p, 1, sz, f);
    p[sz] = 0;
  }
  fclose(f);
  f = 0;
  if( x!=sz ){
    sqlite3_result_error(context, "could not read back the whole file", -1);
    goto edit_func_end;
  }
  if( bBin ){
    sqlite3_result_blob64(context, p, sz, sqlite3_free);
  }else{
    sqlite3_result_text64(context, (const char*)p, sz,
                          sqlite3_free, SQLITE_UTF8);
  }
  p = 0;

edit_func_end:
  if( f ) fclose(f);
  unlink(zTempFile);
  sqlite3_free(zTempFile);
  sqlite3_free(p);
}

/*
** Save or restore the current output mode
*/
static void outputModePush(ShellState *p){
  p->modePrior = p->mode;
  memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
  memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
}
static void outputModePop(ShellState *p){
  p->mode = p->modePrior;
  memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
  memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
}

/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
  int i;
  char *zBlob = (char *)pBlob;
1387
1388
1389
1390
1391
1392
1393
















1394
1395
1396
1397
1398
1399
1400
static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
  char c = z[n];
  z[n] = 0;
  printSchemaLine(out, z, zTail);
  z[n] = c;
}

















/*
** This is the callback routine that the shell
** invokes for each row of a query result.
*/
static int shell_callback(
  void *pArg,
  int nArg,        /* Number of result columns */







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







1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
  char c = z[n];
  z[n] = 0;
  printSchemaLine(out, z, zTail);
  z[n] = c;
}

/*
** Return true if string z[] has nothing but whitespace and comments to the
** end of the first line.
*/
static int wsToEol(const char *z){
  int i;
  for(i=0; z[i]; i++){
    if( z[i]=='\n' ) return 1;
    if( IsSpace(z[i]) ) continue;
    if( z[i]=='-' && z[i+1]=='-' ) return 1;
    return 0;
  }
  return 1;
}
    

/*
** This is the callback routine that the shell
** invokes for each row of a query result.
*/
static int shell_callback(
  void *pArg,
  int nArg,        /* Number of result columns */
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539


1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550


1551
1552
1553
1554
1555
1556
1557
          j--;
        }
        z[j++] = c;
      }
      while( j>0 && IsSpace(z[j-1]) ){ j--; }
      z[j] = 0;
      if( strlen30(z)>=79 ){
        for(i=j=0; (c = z[i])!=0; i++){
          if( c==cEnd ){
            cEnd = 0;
          }else if( c=='"' || c=='\'' || c=='`' ){
            cEnd = c;
          }else if( c=='[' ){
            cEnd = ']';


          }else if( c=='(' ){
            nParen++;
          }else if( c==')' ){
            nParen--;
            if( nLine>0 && nParen==0 && j>0 ){
              printSchemaLineN(p->out, z, j, "\n");
              j = 0;
            }
          }
          z[j++] = c;
          if( nParen==1 && (c=='(' || c==',' || c=='\n') ){


            if( c=='\n' ) j--;
            printSchemaLineN(p->out, z, j, "\n  ");
            j = 0;
            nLine++;
            while( IsSpace(z[i+1]) ){ i++; }
          }
        }







|






>
>










|
>
>







1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
          j--;
        }
        z[j++] = c;
      }
      while( j>0 && IsSpace(z[j-1]) ){ j--; }
      z[j] = 0;
      if( strlen30(z)>=79 ){
        for(i=j=0; (c = z[i])!=0; i++){  /* Copy changes from z[i] back to z[j] */
          if( c==cEnd ){
            cEnd = 0;
          }else if( c=='"' || c=='\'' || c=='`' ){
            cEnd = c;
          }else if( c=='[' ){
            cEnd = ']';
          }else if( c=='-' && z[i+1]=='-' ){
            cEnd = '\n';
          }else if( c=='(' ){
            nParen++;
          }else if( c==')' ){
            nParen--;
            if( nLine>0 && nParen==0 && j>0 ){
              printSchemaLineN(p->out, z, j, "\n");
              j = 0;
            }
          }
          z[j++] = c;
          if( nParen==1 && cEnd==0
           && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
          ){
            if( c=='\n' ) j--;
            printSchemaLineN(p->out, z, j, "\n  ");
            j = 0;
            nLine++;
            while( IsSpace(z[i+1]) ){ i++; }
          }
        }
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
      { "syscw: ",                  "Write() system calls:"     },
      { "read_bytes: ",             "Bytes read from storage:"  },
      { "write_bytes: ",            "Bytes written to storage:" },
      { "cancelled_write_bytes: ",  "Cancelled write bytes:"    },
    };
    int i;
    for(i=0; i<ArraySize(aTrans); i++){
      int n = (int)strlen(aTrans[i].zPattern);
      if( strncmp(aTrans[i].zPattern, z, n)==0 ){
        utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
        break;
      }
    }
  }
  fclose(in);







|







2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
      { "syscw: ",                  "Write() system calls:"     },
      { "read_bytes: ",             "Bytes read from storage:"  },
      { "write_bytes: ",            "Bytes written to storage:" },
      { "cancelled_write_bytes: ",  "Cancelled write bytes:"    },
    };
    int i;
    for(i=0; i<ArraySize(aTrans); i++){
      int n = strlen30(aTrans[i].zPattern);
      if( strncmp(aTrans[i].zPattern, z, n)==0 ){
        utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
        break;
      }
    }
  }
  fclose(in);
2342
2343
2344
2345
2346
2347
2348

2349
2350
2351
2352
2353
2354
2355
      do{
        rc = sqlite3_step(pStmt);
      } while( rc == SQLITE_ROW );
    }
  }
}


/*
** This function is called to process SQL if the previous shell command
** was ".expert". It passes the SQL in the second argument directly to
** the sqlite3expert object.
**
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
** code. In this case, (*pzErr) may be set to point to a buffer containing







>







2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
      do{
        rc = sqlite3_step(pStmt);
      } while( rc == SQLITE_ROW );
    }
  }
}

#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** This function is called to process SQL if the previous shell command
** was ".expert". It passes the SQL in the second argument directly to
** the sqlite3expert object.
**
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
** code. In this case, (*pzErr) may be set to point to a buffer containing
2414
2415
2416
2417
2418
2419
2420

























































2421
2422
2423
2424
2425
2426
2427
    }
  }
  sqlite3_expert_destroy(p);
  pState->expert.pExpert = 0;
  return rc;
}



























































/*
** Execute a statement or set of statements.  Print
** any result rows/columns depending on the current mode
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec()







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







2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
    }
  }
  sqlite3_expert_destroy(p);
  pState->expert.pExpert = 0;
  return rc;
}

/*
** Implementation of ".expert" dot command.
*/
static int expertDotCommand(
  ShellState *pState,             /* Current shell tool state */
  char **azArg,                   /* Array of arguments passed to dot command */
  int nArg                        /* Number of entries in azArg[] */
){
  int rc = SQLITE_OK;
  char *zErr = 0;
  int i;
  int iSample = 0;

  assert( pState->expert.pExpert==0 );
  memset(&pState->expert, 0, sizeof(ExpertInfo));

  for(i=1; rc==SQLITE_OK && i<nArg; i++){
    char *z = azArg[i];
    int n;
    if( z[0]=='-' && z[1]=='-' ) z++;
    n = strlen30(z);
    if( n>=2 && 0==strncmp(z, "-verbose", n) ){
      pState->expert.bVerbose = 1;
    }
    else if( n>=2 && 0==strncmp(z, "-sample", n) ){
      if( i==(nArg-1) ){
        raw_printf(stderr, "option requires an argument: %s\n", z);
        rc = SQLITE_ERROR;
      }else{
        iSample = (int)integerValue(azArg[++i]);
        if( iSample<0 || iSample>100 ){
          raw_printf(stderr, "value out of range: %s\n", azArg[i]);
          rc = SQLITE_ERROR;
        }
      }
    }
    else{
      raw_printf(stderr, "unknown option: %s\n", z);
      rc = SQLITE_ERROR;
    }
  }

  if( rc==SQLITE_OK ){
    pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
    if( pState->expert.pExpert==0 ){
      raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr);
      rc = SQLITE_ERROR;
    }else{
      sqlite3_expert_config(
          pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
      );
    }
  }

  return rc;
}
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */

/*
** Execute a statement or set of statements.  Print
** any result rows/columns depending on the current mode
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec()
2441
2442
2443
2444
2445
2446
2447

2448
2449
2450
2451

2452
2453
2454
2455
2456
2457
2458
  int rc2;
  const char *zLeftover;          /* Tail of unprocessed SQL */

  if( pzErrMsg ){
    *pzErrMsg = NULL;
  }


  if( pArg->expert.pExpert ){
    rc = expertHandleSQL(pArg, zSql, pzErrMsg);
    return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
  }


  while( zSql[0] && (SQLITE_OK == rc) ){
    static const char *zStmtSql;
    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
    if( SQLITE_OK != rc ){
      if( pzErrMsg ){
        *pzErrMsg = save_err_msg(db);







>




>







2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
  int rc2;
  const char *zLeftover;          /* Tail of unprocessed SQL */

  if( pzErrMsg ){
    *pzErrMsg = NULL;
  }

#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( pArg->expert.pExpert ){
    rc = expertHandleSQL(pArg, zSql, pzErrMsg);
    return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
  }
#endif

  while( zSql[0] && (SQLITE_OK == rc) ){
    static const char *zStmtSql;
    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
    if( SQLITE_OK != rc ){
      if( pzErrMsg ){
        *pzErrMsg = save_err_msg(db);
2851
2852
2853
2854
2855
2856
2857



2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874

2875
2876
2877
2878
2879
2880
2881
  return rc;
}

/*
** Text of a help message
*/
static char zHelp[] =



#ifndef SQLITE_OMIT_AUTHORIZATION
  ".auth ON|OFF           Show authorizer callbacks\n"
#endif
  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
  ".bail on|off           Stop after hitting an error.  Default OFF\n"
  ".binary on|off         Turn binary output on or off.  Default OFF\n"
  ".cd DIRECTORY          Change the working directory to DIRECTORY\n"
  ".changes on|off        Show number of rows changed by SQL\n"
  ".check GLOB            Fail if output since .testcase does not match\n"
  ".clone NEWDB           Clone data into NEWDB from the existing database\n"
  ".databases             List names and files of attached databases\n"
  ".dbinfo ?DB?           Show status information about the database\n"
  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
  "                         If TABLE specified, only dump tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".echo on|off           Turn command echo on or off\n"
  ".eqp on|off|full       Enable or disable automatic EXPLAIN QUERY PLAN\n"

  ".exit                  Exit this program\n"
  ".expert                EXPERIMENTAL. Suggest indexes for specified queries\n"
/* Because explain mode comes on automatically now, the ".explain" mode
** is removed from the help screen.  It is still supported for legacy, however */
/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
  ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
  ".headers on|off        Turn display of headers on or off\n"







>
>
>

















>







3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
  return rc;
}

/*
** Text of a help message
*/
static char zHelp[] =
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
  ".archive ...           Manage SQL archives: \".archive --help\" for details\n"
#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
  ".auth ON|OFF           Show authorizer callbacks\n"
#endif
  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
  ".bail on|off           Stop after hitting an error.  Default OFF\n"
  ".binary on|off         Turn binary output on or off.  Default OFF\n"
  ".cd DIRECTORY          Change the working directory to DIRECTORY\n"
  ".changes on|off        Show number of rows changed by SQL\n"
  ".check GLOB            Fail if output since .testcase does not match\n"
  ".clone NEWDB           Clone data into NEWDB from the existing database\n"
  ".databases             List names and files of attached databases\n"
  ".dbinfo ?DB?           Show status information about the database\n"
  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
  "                         If TABLE specified, only dump tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".echo on|off           Turn command echo on or off\n"
  ".eqp on|off|full       Enable or disable automatic EXPLAIN QUERY PLAN\n"
  ".excel                 Display the output of next command in a spreadsheet\n"
  ".exit                  Exit this program\n"
  ".expert                EXPERIMENTAL. Suggest indexes for specified queries\n"
/* Because explain mode comes on automatically now, the ".explain" mode
** is removed from the help screen.  It is still supported for legacy, however */
/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
  ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
  ".headers on|off        Turn display of headers on or off\n"
2905
2906
2907
2908
2909
2910
2911
2912


2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
  "                         insert   SQL insert statements for TABLE\n"
  "                         line     One value per line\n"
  "                         list     Values delimited by \"|\"\n"
  "                         quote    Escape answers as for SQL\n"
  "                         tabs     Tab-separated values\n"
  "                         tcl      TCL list elements\n"
  ".nullvalue STRING      Use STRING in place of NULL values\n"
  ".once FILENAME         Output for the next SQL command only to FILENAME\n"


  ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
  "                         The --new option starts with an empty file\n"
  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
  ".print STRING...       Print literal STRING\n"
  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
  ".quit                  Exit this program\n"
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
  ".save FILE             Write in-memory database into FILE\n"
  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"







|
>
>


|







3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
  "                         insert   SQL insert statements for TABLE\n"
  "                         line     One value per line\n"
  "                         list     Values delimited by \"|\"\n"
  "                         quote    Escape answers as for SQL\n"
  "                         tabs     Tab-separated values\n"
  "                         tcl      TCL list elements\n"
  ".nullvalue STRING      Use STRING in place of NULL values\n"
  ".once (-e|-x|FILE)     Output for the next SQL command only to FILE\n"
  "                         or invoke system text editor (-e) or spreadsheet (-x)\n"
  "                         on the output.\n"
  ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
  "                         The --new option starts with an empty file\n"
  ".output ?FILE?         Send output to FILE or stdout\n"
  ".print STRING...       Print literal STRING\n"
  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
  ".quit                  Exit this program\n"
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
  ".save FILE             Write in-memory database into FILE\n"
  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
3053
3054
3055
3056
3057
3058
3059


























3060
3061
3062
3063
3064
3065
3066
3067















3068



3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081




3082
3083
3084
3085












3086
3087
3088
3089
3090
3091
3092
  int i;
  for(i=0; i<pSession->nFilter; i++){
    if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
  }
  return 1;
}
#endif



























/*
** Make sure the database is open.  If it is not, then open it.  If
** the database fails to open, print an error message and exit.
*/
static void open_db(ShellState *p, int keepAlive){
  if( p->db==0 ){
    sqlite3_initialize();















    sqlite3_open(p->zDbFilename, &p->db);



    globalDb = p->db;
    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
      utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
          p->zDbFilename, sqlite3_errmsg(p->db));
      if( keepAlive ) return;
      exit(1);
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_shathree_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);




    sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
                            shellAddSchemaName, 0, 0);
    sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
                            shellModuleSchema, 0, 0);












  }
}

#if HAVE_READLINE || HAVE_EDITLINE
/*
** Readline completion callbacks
*/







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








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













>
>
>
>




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







3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
  int i;
  for(i=0; i<pSession->nFilter; i++){
    if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
  }
  return 1;
}
#endif

/*
** Try to deduce the type of file for zName based on its content.  Return
** one of the SHELL_OPEN_* constants.
*/
static int deduceDatabaseType(const char *zName){
  FILE *f = fopen(zName, "rb");
  size_t n;
  int rc = SHELL_OPEN_UNSPEC;
  char zBuf[100];
  if( f==0 ) return SHELL_OPEN_NORMAL;
  fseek(f, -25, SEEK_END);
  n = fread(zBuf, 25, 1, f);
  if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
    rc = SHELL_OPEN_APPENDVFS;
  }else{
    fseek(f, -22, SEEK_END);
    n = fread(zBuf, 22, 1, f);
    if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
       && zBuf[3]==0x06 ){
      rc = SHELL_OPEN_ZIPFILE;
    }
  }
  fclose(f);
  return rc;  
}

/*
** Make sure the database is open.  If it is not, then open it.  If
** the database fails to open, print an error message and exit.
*/
static void open_db(ShellState *p, int keepAlive){
  if( p->db==0 ){
    sqlite3_initialize();
    if( p->openMode==SHELL_OPEN_UNSPEC && access(p->zDbFilename,0)==0 ){
      p->openMode = (u8)deduceDatabaseType(p->zDbFilename);
    }
    switch( p->openMode ){
      case SHELL_OPEN_APPENDVFS: {
        sqlite3_open_v2(p->zDbFilename, &p->db, 
           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs");
        break;
      }
      case SHELL_OPEN_ZIPFILE: {
        sqlite3_open(":memory:", &p->db);
        break;
      }
      case SHELL_OPEN_UNSPEC:
      case SHELL_OPEN_NORMAL: {
        sqlite3_open(p->zDbFilename, &p->db);
        break;
      }
    }
    globalDb = p->db;
    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
      utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
          p->zDbFilename, sqlite3_errmsg(p->db));
      if( keepAlive ) return;
      exit(1);
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_shathree_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);
#ifdef SQLITE_HAVE_ZLIB
    sqlite3_zipfile_init(p->db, 0, 0);
    sqlite3_sqlar_init(p->db, 0, 0);
#endif
    sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
                            shellAddSchemaName, 0, 0);
    sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
                            shellModuleSchema, 0, 0);
    sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
                            shellPutsFunc, 0, 0);
    sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
                            editFunc, 0, 0);
    sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
                            editFunc, 0, 0);
    if( p->openMode==SHELL_OPEN_ZIPFILE ){
      char *zSql = sqlite3_mprintf(
         "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename);
      sqlite3_exec(p->db, zSql, 0, 0, 0);
      sqlite3_free(zSql);
    }
  }
}

#if HAVE_READLINE || HAVE_EDITLINE
/*
** Readline completion callbacks
*/
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
}

#elif HAVE_LINENOISE
/*
** Linenoise completion callback
*/
static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
  int nLine = (int)strlen(zLine);
  int i, iStart;
  sqlite3_stmt *pStmt = 0;
  char *zSql;
  char zBuf[1000];

  if( nLine>sizeof(zBuf)-30 ) return;
  if( zLine[0]=='.' ) return;







|







3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
}

#elif HAVE_LINENOISE
/*
** Linenoise completion callback
*/
static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
  int nLine = strlen30(zLine);
  int i, iStart;
  sqlite3_stmt *pStmt = 0;
  char *zSql;
  char zBuf[1000];

  if( nLine>sizeof(zBuf)-30 ) return;
  if( zLine[0]=='.' ) return;
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
      }
    }
    z[j] = c;
  }
  if( j<i ) z[j] = 0;
}

/*
** Return the value of a hexadecimal digit.  Return -1 if the input
** is not a hex digit.
*/
static int hexDigitValue(char c){
  if( c>='0' && c<='9' ) return c - '0';
  if( c>='a' && c<='f' ) return c - 'a' + 10;
  if( c>='A' && c<='F' ) return c - 'A' + 10;
  return -1;
}

/*
** Interpret zArg as an integer value, possibly with suffixes.
*/
static sqlite3_int64 integerValue(const char *zArg){
  sqlite3_int64 v = 0;
  static const struct { char *zSuffix; int iMult; } aMult[] = {
    { "KiB", 1024 },
    { "MiB", 1024*1024 },
    { "GiB", 1024*1024*1024 },
    { "KB",  1000 },
    { "MB",  1000000 },
    { "GB",  1000000000 },
    { "K",   1000 },
    { "M",   1000000 },
    { "G",   1000000000 },
  };
  int i;
  int isNeg = 0;
  if( zArg[0]=='-' ){
    isNeg = 1;
    zArg++;
  }else if( zArg[0]=='+' ){
    zArg++;
  }
  if( zArg[0]=='0' && zArg[1]=='x' ){
    int x;
    zArg += 2;
    while( (x = hexDigitValue(zArg[0]))>=0 ){
      v = (v<<4) + x;
      zArg++;
    }
  }else{
    while( IsDigit(zArg[0]) ){
      v = v*10 + zArg[0] - '0';
      zArg++;
    }
  }
  for(i=0; i<ArraySize(aMult); i++){
    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
      v *= aMult[i].iMult;
      break;
    }
  }
  return isNeg? -v : v;
}

/*
** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
** for TRUE and FALSE.  Return the integer value if appropriate.
*/
static int booleanValue(const char *zArg){
  int i;
  if( zArg[0]=='0' && zArg[1]=='x' ){







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







3610
3611
3612
3613
3614
3615
3616

























































3617
3618
3619
3620
3621
3622
3623
      }
    }
    z[j] = c;
  }
  if( j<i ) z[j] = 0;
}


























































/*
** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
** for TRUE and FALSE.  Return the integer value if appropriate.
*/
static int booleanValue(const char *zArg){
  int i;
  if( zArg[0]=='0' && zArg[1]=='x' ){
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
}

/*
** Try to open an output file.   The names "stdout" and "stderr" are
** recognized and do the right thing.  NULL is returned if the output
** filename is "off".
*/
static FILE *output_file_open(const char *zFile){
  FILE *f;
  if( strcmp(zFile,"stdout")==0 ){
    f = stdout;
  }else if( strcmp(zFile, "stderr")==0 ){
    f = stderr;
  }else if( strcmp(zFile, "off")==0 ){
    f = 0;
  }else{
    f = fopen(zFile, "wb");
    if( f==0 ){
      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
    }
  }
  return f;
}








|








|







3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
}

/*
** Try to open an output file.   The names "stdout" and "stderr" are
** recognized and do the right thing.  NULL is returned if the output
** filename is "off".
*/
static FILE *output_file_open(const char *zFile, int bTextMode){
  FILE *f;
  if( strcmp(zFile,"stdout")==0 ){
    f = stdout;
  }else if( strcmp(zFile, "stderr")==0 ){
    f = stderr;
  }else if( strcmp(zFile, "off")==0 ){
    f = 0;
  }else{
    f = fopen(zFile, bTextMode ? "w" : "wb");
    if( f==0 ){
      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
    }
  }
  return f;
}

3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
  void *pX
){
  FILE *f = (FILE*)pArg;
  UNUSED_PARAMETER(mType);
  UNUSED_PARAMETER(pP);
  if( f ){
    const char *z = (const char*)pX;
    int i = (int)strlen(z);
    while( i>0 && z[i-1]==';' ){ i--; }
    utf8_printf(f, "%.*s;\n", i, z);
  }
  return 0;
}
#endif
#endif







|







3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
  void *pX
){
  FILE *f = (FILE*)pArg;
  UNUSED_PARAMETER(mType);
  UNUSED_PARAMETER(pP);
  if( f ){
    const char *z = (const char*)pX;
    int i = strlen30(z);
    while( i>0 && z[i-1]==';' ){ i--; }
    utf8_printf(f, "%.*s;\n", i, z);
  }
  return 0;
}
#endif
#endif
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
){
  sqlite3_stmt *pQuery = 0;
  sqlite3_stmt *pInsert = 0;
  char *zQuery = 0;
  char *zInsert = 0;
  int rc;
  int i, j, n;
  int nTable = (int)strlen(zTable);
  int k = 0;
  int cnt = 0;
  const int spinRate = 10000;

  zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
  if( rc ){
    utf8_printf(stderr, "Error %d: %s on [%s]\n",
            sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
            zQuery);
    goto end_data_xfer;
  }
  n = sqlite3_column_count(pQuery);
  zInsert = sqlite3_malloc64(200 + nTable + n*3);
  if( zInsert==0 ){
    raw_printf(stderr, "out of memory\n");
    goto end_data_xfer;
  }
  sqlite3_snprintf(200+nTable,zInsert,
                   "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
  i = (int)strlen(zInsert);
  for(j=1; j<n; j++){
    memcpy(zInsert+i, ",?", 2);
    i += 2;
  }
  memcpy(zInsert+i, ");", 3);
  rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
  if( rc ){







|




















|







3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
){
  sqlite3_stmt *pQuery = 0;
  sqlite3_stmt *pInsert = 0;
  char *zQuery = 0;
  char *zInsert = 0;
  int rc;
  int i, j, n;
  int nTable = strlen30(zTable);
  int k = 0;
  int cnt = 0;
  const int spinRate = 10000;

  zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
  if( rc ){
    utf8_printf(stderr, "Error %d: %s on [%s]\n",
            sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
            zQuery);
    goto end_data_xfer;
  }
  n = sqlite3_column_count(pQuery);
  zInsert = sqlite3_malloc64(200 + nTable + n*3);
  if( zInsert==0 ){
    raw_printf(stderr, "out of memory\n");
    goto end_data_xfer;
  }
  sqlite3_snprintf(200+nTable,zInsert,
                   "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
  i = strlen30(zInsert);
  for(j=1; j<n; j++){
    memcpy(zInsert+i, ",?", 2);
    i += 2;
  }
  memcpy(zInsert+i, ");", 3);
  rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
  if( rc ){
3731
3732
3733
3734
3735
3736
3737
3738




3739
3740
3741
3742
3743
3744
3745
3746


















3747
3748
3749
3750
3751
3752
3753
    sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
  }
  sqlite3_close(newDb);
}

/*
** Change the output file back to stdout




*/
static void output_reset(ShellState *p){
  if( p->outfile[0]=='|' ){
#ifndef SQLITE_OMIT_POPEN
    pclose(p->out);
#endif
  }else{
    output_file_close(p->out);


















  }
  p->outfile[0] = 0;
  p->out = stdout;
}

/*
** Run an SQL command and return the single integer result.







|
>
>
>
>








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







4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
    sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
  }
  sqlite3_close(newDb);
}

/*
** Change the output file back to stdout.
**
** If the p->doXdgOpen flag is set, that means the output was being
** redirected to a temporary file named by p->zTempFile.  In that case,
** launch start/open/xdg-open on that temporary file.
*/
static void output_reset(ShellState *p){
  if( p->outfile[0]=='|' ){
#ifndef SQLITE_OMIT_POPEN
    pclose(p->out);
#endif
  }else{
    output_file_close(p->out);
    if( p->doXdgOpen ){
      const char *zXdgOpenCmd =
#if defined(_WIN32)
      "start";
#elif defined(__APPLE__)
      "open";
#else
      "xdg-open";
#endif
      char *zCmd;
      zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
      if( system(zCmd) ){
        utf8_printf(stderr, "Failed: [%s]\n", zCmd);
      }
      sqlite3_free(zCmd);
      outputModePop(p);
      p->doXdgOpen = 0;
    }
  }
  p->outfile[0] = 0;
  p->out = stdout;
}

/*
** Run an SQL command and return the single integer result.
3998
3999
4000
4001
4002
4003
4004



































4005
4006
4007
4008
4009
4010
4011
  sqlite3_free(z);
#else
  rc = unlink(zFilename);
#endif
  return rc;
}





































/*
** The implementation of SQL scalar function fkey_collate_clause(), used
** by the ".lint fkey-indexes" command. This scalar function is always
** called with four arguments - the parent table name, the parent column name,
** the child table name and the child column name.
**







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







4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
  sqlite3_free(z);
#else
  rc = unlink(zFilename);
#endif
  return rc;
}

/*
** Try to delete the temporary file (if there is one) and free the
** memory used to hold the name of the temp file.
*/
static void clearTempFile(ShellState *p){
  if( p->zTempFile==0 ) return;
  if( p->doXdgOpen ) return;
  if( shellDeleteFile(p->zTempFile) ) return;
  sqlite3_free(p->zTempFile);
  p->zTempFile = 0;
}

/*
** Create a new temp file name with the given suffix.
*/
static void newTempFile(ShellState *p, const char *zSuffix){
  clearTempFile(p);
  sqlite3_free(p->zTempFile);
  p->zTempFile = 0;
  if( p->db ){
    sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
  }
  if( p->zTempFile==0 ){
    sqlite3_uint64 r;
    sqlite3_randomness(sizeof(r), &r);
    p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix);
  }else{
    p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
  }
  if( p->zTempFile==0 ){
    raw_printf(stderr, "out of memory\n");
    exit(1);
  }
}


/*
** The implementation of SQL scalar function fkey_collate_clause(), used
** by the ".lint fkey-indexes" command. This scalar function is always
** called with four arguments - the parent table name, the parent column name,
** the child table name and the child column name.
**
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
    "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
    "GROUP BY s.name, f.id "
    "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
  ;
  const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";

  for(i=2; i<nArg; i++){
    int n = (int)strlen(azArg[i]);
    if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
      bVerbose = 1;
    }
    else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
      bGroupByParent = 1;
      zIndent = "    ";
    }







|







4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
    "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
    "GROUP BY s.name, f.id "
    "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
  ;
  const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";

  for(i=2; i<nArg; i++){
    int n = strlen30(azArg[i]);
    if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
      bVerbose = 1;
    }
    else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
      bGroupByParent = 1;
      zIndent = "    ";
    }
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253





























































































































































































































































































































































































































































































































































































































4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306





4307










































































4308
4309
4310
4311


4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326

4327
4328
4329

4330
4331
4332
4333
4334
4335
4336
*/
static int lintDotCommand(
  ShellState *pState,             /* Current shell tool state */
  char **azArg,                   /* Array of arguments passed to dot command */
  int nArg                        /* Number of entries in azArg[] */
){
  int n;
  n = (nArg>=2 ? (int)strlen(azArg[1]) : 0);
  if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
  return lintFkeyIndexes(pState, azArg, nArg);

 usage:
  raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
  raw_printf(stderr, "Where sub-commands are:\n");
  raw_printf(stderr, "    fkey-indexes\n");
  return SQLITE_ERROR;
}






























































































































































































































































































































































































































































































































































































































/*
** Implementation of ".expert" dot command.
*/
static int expertDotCommand(
  ShellState *pState,             /* Current shell tool state */
  char **azArg,                   /* Array of arguments passed to dot command */
  int nArg                        /* Number of entries in azArg[] */
){
  int rc = SQLITE_OK;
  char *zErr = 0;
  int i;
  int iSample = 0;

  assert( pState->expert.pExpert==0 );
  memset(&pState->expert, 0, sizeof(ExpertInfo));

  for(i=1; rc==SQLITE_OK && i<nArg; i++){
    char *z = azArg[i];
    int n;
    if( z[0]=='-' && z[1]=='-' ) z++;
    n = strlen30(z);
    if( n>=2 && 0==strncmp(z, "-verbose", n) ){
      pState->expert.bVerbose = 1;
    }
    else if( n>=2 && 0==strncmp(z, "-sample", n) ){
      if( i==(nArg-1) ){
        raw_printf(stderr, "option requires an argument: %s\n", z);
        rc = SQLITE_ERROR;
      }else{
        iSample = (int)integerValue(azArg[++i]);
        if( iSample<0 || iSample>100 ){
          raw_printf(stderr, "value out of range: %s\n", azArg[i]);
          rc = SQLITE_ERROR;
        }
      }
    }
    else{
      raw_printf(stderr, "unknown option: %s\n", z);
      rc = SQLITE_ERROR;
    }
  }

  if( rc==SQLITE_OK ){
    pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
    if( pState->expert.pExpert==0 ){
      raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr);
      rc = SQLITE_ERROR;
    }else{
      sqlite3_expert_config(
          pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
      );
    }





  }











































































  return rc;
}





/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int do_meta_command(char *zLine, ShellState *p){
  int h = 1;
  int nArg = 0;
  int n, c;
  int rc = 0;
  char *azArg[50];


  if( p->expert.pExpert ){
    expertFinish(p, 1, 0);
  }


  /* Parse the input line into tokens.
  */
  while( zLine[h] && nArg<ArraySize(azArg) ){
    while( IsSpace(zLine[h]) ){ h++; }
    if( zLine[h]==0 ) break;
    if( zLine[h]=='\'' || zLine[h]=='"' ){







|









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


|

|




|
<
|
<
|
<
<
|
|
<
|
<
|
<
|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<

<
|
<

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



|
>
>















>



>







4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272

5273

5274


5275
5276

5277

5278

5279


5280















5281





5282

5283

5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
*/
static int lintDotCommand(
  ShellState *pState,             /* Current shell tool state */
  char **azArg,                   /* Array of arguments passed to dot command */
  int nArg                        /* Number of entries in azArg[] */
){
  int n;
  n = (nArg>=2 ? strlen30(azArg[1]) : 0);
  if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
  return lintFkeyIndexes(pState, azArg, nArg);

 usage:
  raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
  raw_printf(stderr, "Where sub-commands are:\n");
  raw_printf(stderr, "    fkey-indexes\n");
  return SQLITE_ERROR;
}

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
/*********************************************************************************
** The ".archive" or ".ar" command.
*/
static void shellPrepare(
  sqlite3 *db, 
  int *pRc, 
  const char *zSql, 
  sqlite3_stmt **ppStmt
){
  *ppStmt = 0;
  if( *pRc==SQLITE_OK ){
    int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
    if( rc!=SQLITE_OK ){
      raw_printf(stderr, "sql error: %s (%d)\n", 
          sqlite3_errmsg(db), sqlite3_errcode(db)
      );
      *pRc = rc;
    }
  }
}

static void shellPreparePrintf(
  sqlite3 *db, 
  int *pRc, 
  sqlite3_stmt **ppStmt,
  const char *zFmt, 
  ...
){
  *ppStmt = 0;
  if( *pRc==SQLITE_OK ){
    va_list ap;
    char *z;
    va_start(ap, zFmt);
    z = sqlite3_vmprintf(zFmt, ap);
    if( z==0 ){
      *pRc = SQLITE_NOMEM;
    }else{
      shellPrepare(db, pRc, z, ppStmt);
      sqlite3_free(z);
    }
  }
}

static void shellFinalize(
  int *pRc, 
  sqlite3_stmt *pStmt
){
  if( pStmt ){
    sqlite3 *db = sqlite3_db_handle(pStmt);
    int rc = sqlite3_finalize(pStmt);
    if( *pRc==SQLITE_OK ){
      if( rc!=SQLITE_OK ){
        raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
      }
      *pRc = rc;
    }
  }
}

static void shellReset(
  int *pRc, 
  sqlite3_stmt *pStmt
){
  int rc = sqlite3_reset(pStmt);
  if( *pRc==SQLITE_OK ){
    if( rc!=SQLITE_OK ){
      sqlite3 *db = sqlite3_db_handle(pStmt);
      raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
    }
    *pRc = rc;
  }
}
/*
** Structure representing a single ".ar" command.
*/
typedef struct ArCommand ArCommand;
struct ArCommand {
  u8 eCmd;                        /* An AR_CMD_* value */
  u8 bVerbose;                    /* True if --verbose */
  u8 bZip;                        /* True if the archive is a ZIP */
  u8 bDryRun;                     /* True if --dry-run */
  u8 bAppend;                     /* True if --append */
  int nArg;                       /* Number of command arguments */
  char *zSrcTable;                /* "sqlar", "zipfile($file)" or "zip" */
  const char *zFile;              /* --file argument, or NULL */
  const char *zDir;               /* --directory argument, or NULL */
  char **azArg;                   /* Array of command arguments */
  ShellState *p;                  /* Shell state */
  sqlite3 *db;                    /* Database containing the archive */
};

/*
** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
*/
static int arUsage(FILE *f){
  raw_printf(f,
"\n"
"Usage: .ar [OPTION...] [FILE...]\n"
"The .ar command manages sqlar archives.\n"
"\n"
"Examples:\n"
"  .ar -cf archive.sar foo bar    # Create archive.sar from files foo and bar\n"
"  .ar -tf archive.sar            # List members of archive.sar\n"
"  .ar -xvf archive.sar           # Verbosely extract files from archive.sar\n"
"\n"
"Each command line must feature exactly one command option:\n"
"  -c, --create               Create a new archive\n"
"  -u, --update               Update or add files to an existing archive\n"
"  -t, --list                 List contents of archive\n"
"  -x, --extract              Extract files from archive\n"
"\n"
"And zero or more optional options:\n"
"  -v, --verbose              Print each filename as it is processed\n"
"  -f FILE, --file FILE       Operate on archive FILE (default is current db)\n"
"  -a FILE, --append FILE     Operate on FILE opened using the apndvfs VFS\n"
"  -C DIR, --directory DIR    Change to directory DIR to read/extract files\n"
"  -n, --dryrun               Show the SQL that would have occurred\n"
"\n"
"See also: http://sqlite.org/cli.html#sqlar_archive_support\n"
"\n"
);
  return SQLITE_ERROR;
}

/*
** Print an error message for the .ar command to stderr and return 
** SQLITE_ERROR.
*/
static int arErrorMsg(const char *zFmt, ...){
  va_list ap;
  char *z;
  va_start(ap, zFmt);
  z = sqlite3_vmprintf(zFmt, ap);
  va_end(ap);
  raw_printf(stderr, "Error: %s (try \".ar --help\")\n", z);
  sqlite3_free(z);
  return SQLITE_ERROR;
}

/*
** Values for ArCommand.eCmd.
*/
#define AR_CMD_CREATE       1
#define AR_CMD_EXTRACT      2
#define AR_CMD_LIST         3
#define AR_CMD_UPDATE       4
#define AR_CMD_HELP         5

/*
** Other (non-command) switches.
*/
#define AR_SWITCH_VERBOSE     6
#define AR_SWITCH_FILE        7
#define AR_SWITCH_DIRECTORY   8
#define AR_SWITCH_APPEND      9
#define AR_SWITCH_DRYRUN     10

static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
  switch( eSwitch ){
    case AR_CMD_CREATE:
    case AR_CMD_EXTRACT:
    case AR_CMD_LIST:
    case AR_CMD_UPDATE:
    case AR_CMD_HELP:
      if( pAr->eCmd ){
        return arErrorMsg("multiple command options");
      }
      pAr->eCmd = eSwitch;
      break;

    case AR_SWITCH_DRYRUN:
      pAr->bDryRun = 1;
      break;
    case AR_SWITCH_VERBOSE:
      pAr->bVerbose = 1;
      break;
    case AR_SWITCH_APPEND:
      pAr->bAppend = 1;
      /* Fall thru into --file */
    case AR_SWITCH_FILE:
      pAr->zFile = zArg;
      break;
    case AR_SWITCH_DIRECTORY:
      pAr->zDir = zArg;
      break;
  }

  return SQLITE_OK;
}

/*
** Parse the command line for an ".ar" command. The results are written into
** structure (*pAr). SQLITE_OK is returned if the command line is parsed
** successfully, otherwise an error message is written to stderr and 
** SQLITE_ERROR returned.
*/
static int arParseCommand(
  char **azArg,                   /* Array of arguments passed to dot command */
  int nArg,                       /* Number of entries in azArg[] */
  ArCommand *pAr                  /* Populate this object */
){
  struct ArSwitch {
    const char *zLong;
    char cShort;
    u8 eSwitch;
    u8 bArg;
  } aSwitch[] = {
    { "create",    'c', AR_CMD_CREATE,       0 },
    { "extract",   'x', AR_CMD_EXTRACT,      0 },
    { "list",      't', AR_CMD_LIST,         0 },
    { "update",    'u', AR_CMD_UPDATE,       0 },
    { "help",      'h', AR_CMD_HELP,         0 },
    { "verbose",   'v', AR_SWITCH_VERBOSE,   0 },
    { "file",      'f', AR_SWITCH_FILE,      1 },
    { "append",    'a', AR_SWITCH_APPEND,    1 },
    { "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
    { "dryrun",    'n', AR_SWITCH_DRYRUN,    0 },
  };
  int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
  struct ArSwitch *pEnd = &aSwitch[nSwitch];

  if( nArg<=1 ){
    return arUsage(stderr);
  }else{
    char *z = azArg[1];
    memset(pAr, 0, sizeof(ArCommand));

    if( z[0]!='-' ){
      /* Traditional style [tar] invocation */
      int i;
      int iArg = 2;
      for(i=0; z[i]; i++){
        const char *zArg = 0;
        struct ArSwitch *pOpt;
        for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
          if( z[i]==pOpt->cShort ) break;
        }
        if( pOpt==pEnd ){
          return arErrorMsg("unrecognized option: %c", z[i]);
        }
        if( pOpt->bArg ){
          if( iArg>=nArg ){
            return arErrorMsg("option requires an argument: %c",z[i]);
          }
          zArg = azArg[iArg++];
        }
        if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
      }
      pAr->nArg = nArg-iArg;
      if( pAr->nArg>0 ){
        pAr->azArg = &azArg[iArg];
      }
    }else{
      /* Non-traditional invocation */
      int iArg;
      for(iArg=1; iArg<nArg; iArg++){
        int n;
        z = azArg[iArg];
        if( z[0]!='-' ){
          /* All remaining command line words are command arguments. */
          pAr->azArg = &azArg[iArg];
          pAr->nArg = nArg-iArg;
          break;
        }
        n = strlen30(z);

        if( z[1]!='-' ){
          int i;
          /* One or more short options */
          for(i=1; i<n; i++){
            const char *zArg = 0;
            struct ArSwitch *pOpt;
            for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
              if( z[i]==pOpt->cShort ) break;
            }
            if( pOpt==pEnd ){
              return arErrorMsg("unrecognized option: %c\n", z[i]);
            }
            if( pOpt->bArg ){
              if( i<(n-1) ){
                zArg = &z[i+1];
                i = n;
              }else{
                if( iArg>=(nArg-1) ){
                  return arErrorMsg("option requires an argument: %c\n",z[i]);
                }
                zArg = azArg[++iArg];
              }
            }
            if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
          }
        }else if( z[2]=='\0' ){
          /* A -- option, indicating that all remaining command line words
          ** are command arguments.  */
          pAr->azArg = &azArg[iArg+1];
          pAr->nArg = nArg-iArg-1;
          break;
        }else{
          /* A long option */
          const char *zArg = 0;             /* Argument for option, if any */
          struct ArSwitch *pMatch = 0;      /* Matching option */
          struct ArSwitch *pOpt;            /* Iterator */
          for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
            const char *zLong = pOpt->zLong;
            if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
              if( pMatch ){
                return arErrorMsg("ambiguous option: %s",z);
              }else{
                pMatch = pOpt;
              }
            }
          }

          if( pMatch==0 ){
            return arErrorMsg("unrecognized option: %s", z);
          }
          if( pMatch->bArg ){
            if( iArg>=(nArg-1) ){
              return arErrorMsg("option requires an argument: %s", z);
            }
            zArg = azArg[++iArg];
          }
          if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR;
        }
      }
    }
  }

  return SQLITE_OK;
}

/*
** This function assumes that all arguments within the ArCommand.azArg[]
** array refer to archive members, as for the --extract or --list commands. 
** It checks that each of them are present. If any specified file is not
** present in the archive, an error is printed to stderr and an error
** code returned. Otherwise, if all specified arguments are present in
** the archive, SQLITE_OK is returned.
**
** This function strips any trailing '/' characters from each argument.
** This is consistent with the way the [tar] command seems to work on
** Linux.
*/
static int arCheckEntries(ArCommand *pAr){
  int rc = SQLITE_OK;
  if( pAr->nArg ){
    int i, j;
    sqlite3_stmt *pTest = 0;

    shellPreparePrintf(pAr->db, &rc, &pTest,
        "SELECT name FROM %s WHERE name=$name", 
        pAr->zSrcTable
    );
    j = sqlite3_bind_parameter_index(pTest, "$name");
    for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
      char *z = pAr->azArg[i];
      int n = strlen30(z);
      int bOk = 0;
      while( n>0 && z[n-1]=='/' ) n--;
      z[n] = '\0';
      sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC);
      if( SQLITE_ROW==sqlite3_step(pTest) ){
        bOk = 1;
      }
      shellReset(&rc, pTest);
      if( rc==SQLITE_OK && bOk==0 ){
        utf8_printf(stderr, "not found in archive: %s\n", z);
        rc = SQLITE_ERROR;
      }
    }
    shellFinalize(&rc, pTest);
  }
  return rc;
}

/*
** Format a WHERE clause that can be used against the "sqlar" table to
** identify all archive members that match the command arguments held
** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning.
** The caller is responsible for eventually calling sqlite3_free() on
** any non-NULL (*pzWhere) value.
*/
static void arWhereClause(
  int *pRc, 
  ArCommand *pAr, 
  char **pzWhere                  /* OUT: New WHERE clause */
){
  char *zWhere = 0;
  if( *pRc==SQLITE_OK ){
    if( pAr->nArg==0 ){
      zWhere = sqlite3_mprintf("1");
    }else{
      int i;
      const char *zSep = "";
      for(i=0; i<pAr->nArg; i++){
        const char *z = pAr->azArg[i];
        zWhere = sqlite3_mprintf(
          "%z%s name = '%q' OR substr(name,1,%d) = '%q/'", 
          zWhere, zSep, z, strlen30(z)+1, z
        );
        if( zWhere==0 ){
          *pRc = SQLITE_NOMEM;
          break;
        }
        zSep = " OR ";
      }
    }
  }
  *pzWhere = zWhere;
}

/*
** Implementation of .ar "lisT" command. 
*/
static int arListCommand(ArCommand *pAr){
  const char *zSql = "SELECT %s FROM %s WHERE %s"; 
  const char *azCols[] = {
    "name",
    "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name"
  };

  char *zWhere = 0;
  sqlite3_stmt *pSql = 0;
  int rc;

  rc = arCheckEntries(pAr);
  arWhereClause(&rc, pAr, &zWhere);

  shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
                     pAr->zSrcTable, zWhere);
  if( pAr->bDryRun ){
    utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
  }else{
    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
      if( pAr->bVerbose ){
        utf8_printf(pAr->p->out, "%s % 10d  %s  %s\n",
            sqlite3_column_text(pSql, 0),
            sqlite3_column_int(pSql, 1), 
            sqlite3_column_text(pSql, 2),
            sqlite3_column_text(pSql, 3)
        );
      }else{
        utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
      }
    }
  }
  shellFinalize(&rc, pSql);
  return rc;
}


/*
** Implementation of .ar "eXtract" command. 
*/
static int arExtractCommand(ArCommand *pAr){
  const char *zSql1 = 
    "SELECT "
    " ($dir || name),"
    " writefile(($dir || name), %s, mode, mtime) "
    "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)";

  const char *azExtraArg[] = { 
    "sqlar_uncompress(data, sz)",
    "data"
  };

  sqlite3_stmt *pSql = 0;
  int rc = SQLITE_OK;
  char *zDir = 0;
  char *zWhere = 0;
  int i, j;

  /* If arguments are specified, check that they actually exist within
  ** the archive before proceeding. And formulate a WHERE clause to
  ** match them.  */
  rc = arCheckEntries(pAr);
  arWhereClause(&rc, pAr, &zWhere);

  if( rc==SQLITE_OK ){
    if( pAr->zDir ){
      zDir = sqlite3_mprintf("%s/", pAr->zDir);
    }else{
      zDir = sqlite3_mprintf("");
    }
    if( zDir==0 ) rc = SQLITE_NOMEM;
  }

  shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, 
      azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
  );

  if( rc==SQLITE_OK ){
    j = sqlite3_bind_parameter_index(pSql, "$dir");
    sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);

    /* Run the SELECT statement twice. The first time, writefile() is called
    ** for all archive members that should be extracted. The second time,
    ** only for the directories. This is because the timestamps for
    ** extracted directories must be reset after they are populated (as
    ** populating them changes the timestamp).  */
    for(i=0; i<2; i++){
      j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
      sqlite3_bind_int(pSql, j, i);
      if( pAr->bDryRun ){
        utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
      }else{
        while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
          if( i==0 && pAr->bVerbose ){
            utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
          }
        }
      }
      shellReset(&rc, pSql);
    }
    shellFinalize(&rc, pSql);
  }

  sqlite3_free(zDir);
  sqlite3_free(zWhere);
  return rc;
}

/*
** Run the SQL statement in zSql.  Or if doing a --dryrun, merely print it out.
*/
static int arExecSql(ArCommand *pAr, const char *zSql){
  int rc;
  if( pAr->bDryRun ){
    utf8_printf(pAr->p->out, "%s\n", zSql);
    rc = SQLITE_OK;
  }else{
    char *zErr = 0;
    rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
    if( zErr ){
      utf8_printf(stdout, "ERROR: %s\n", zErr);
      sqlite3_free(zErr);
    }
  }
  return rc;
}


/*
** Implementation of .ar "create" and "update" commands.
**
** Create the "sqlar" table in the database if it does not already exist.
** Then add each file in the azFile[] array to the archive. Directories
** are added recursively. If argument bVerbose is non-zero, a message is
** printed on stdout for each file archived.
**
** The create command is the same as update, except that it drops
** any existing "sqlar" table before beginning.
*/
static int arCreateOrUpdateCommand(
  ArCommand *pAr,                 /* Command arguments and options */
  int bUpdate                     /* true for a --create.  false for --update */
){
  const char *zCreate = 
      "CREATE TABLE IF NOT EXISTS sqlar(\n"
      "  name TEXT PRIMARY KEY,  -- name of the file\n"
      "  mode INT,               -- access permissions\n"
      "  mtime INT,              -- last modification time\n"
      "  sz INT,                 -- original file size\n"
      "  data BLOB               -- compressed content\n"
      ")";
  const char *zDrop = "DROP TABLE IF EXISTS sqlar";
  const char *zInsertFmt = 
     "REPLACE INTO sqlar(name,mode,mtime,sz,data)\n"
     "  SELECT\n"
     "    %s,\n"
     "    mode,\n"
     "    mtime,\n"
     "    CASE substr(lsmode(mode),1,1)\n"
     "      WHEN '-' THEN length(data)\n"
     "      WHEN 'd' THEN 0\n"
     "      ELSE -1 END,\n"
     "    CASE WHEN lsmode(mode) LIKE 'd%%' THEN NULL else data END\n"
     "  FROM fsdir(%Q,%Q)\n"
     "  WHERE lsmode(mode) NOT LIKE '?%%';";
  int i;                          /* For iterating through azFile[] */
  int rc;                         /* Return code */

  rc = arExecSql(pAr, "SAVEPOINT ar;");
  if( rc!=SQLITE_OK ) return rc;
  if( bUpdate==0 ){
    rc = arExecSql(pAr, zDrop);
    if( rc!=SQLITE_OK ) return rc;
  }
  rc = arExecSql(pAr, zCreate);
  for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
    char *zSql = sqlite3_mprintf(zInsertFmt,
        pAr->bVerbose ? "shell_putsnl(name)" : "name",
        pAr->azArg[i], pAr->zDir);
    rc = arExecSql(pAr, zSql);
    sqlite3_free(zSql);
  }
  if( rc!=SQLITE_OK ){
    arExecSql(pAr, "ROLLBACK TO ar; RELEASE ar;");
  }else{
    rc = arExecSql(pAr, "RELEASE ar;");
  }
  return rc;
}

/*
** Implementation of ".ar" dot command.
*/
static int arDotCommand(
  ShellState *pState,             /* Current shell tool state */
  char **azArg,                   /* Array of arguments passed to dot command */
  int nArg                        /* Number of entries in azArg[] */
){
  ArCommand cmd;

  int rc;

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


  rc = arParseCommand(azArg, nArg, &cmd);
  if( rc==SQLITE_OK ){

    int eDbType = SHELL_OPEN_UNSPEC;

    cmd.p = pState;

    cmd.db = pState->db;


    if( cmd.zFile ){















      eDbType = deduceDatabaseType(cmd.zFile);





    }else{

      eDbType = pState->openMode;

    }
    if( eDbType==SHELL_OPEN_ZIPFILE ){
      if( cmd.zFile==0 ){
        cmd.zSrcTable = sqlite3_mprintf("zip");
      }else{
        cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
      }
      if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
        utf8_printf(stderr, "zip archives are read-only\n");
        rc = SQLITE_ERROR;
        goto end_ar_command;
      }
      cmd.bZip = 1;
    }else if( cmd.zFile ){
      int flags;
      if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
      if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
        flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
      }else{
        flags = SQLITE_OPEN_READONLY;
      }
      cmd.db = 0;
      if( cmd.bDryRun ){
        utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
             eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
      }
      rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, 
             eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
      if( rc!=SQLITE_OK ){
        utf8_printf(stderr, "cannot open file: %s (%s)\n", 
            cmd.zFile, sqlite3_errmsg(cmd.db)
        );
        goto end_ar_command;
      }
      sqlite3_fileio_init(cmd.db, 0, 0);
#ifdef SQLITE_HAVE_ZLIB
      sqlite3_sqlar_init(cmd.db, 0, 0);
#endif
      sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
                              shellPutsFunc, 0, 0);

    }
    if( cmd.zSrcTable==0 ){
      if( cmd.eCmd!=AR_CMD_CREATE
       && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
      ){
        utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
        rc = SQLITE_ERROR;
        goto end_ar_command;
      }
      cmd.zSrcTable = sqlite3_mprintf("sqlar");
    }

    switch( cmd.eCmd ){
      case AR_CMD_CREATE:
        rc = arCreateOrUpdateCommand(&cmd, 0);
        break;

      case AR_CMD_EXTRACT:
        rc = arExtractCommand(&cmd);
        break;

      case AR_CMD_LIST:
        rc = arListCommand(&cmd);
        break;

      case AR_CMD_HELP:
        arUsage(pState->out);
        break;

      default:
        assert( cmd.eCmd==AR_CMD_UPDATE );
        rc = arCreateOrUpdateCommand(&cmd, 1);
        break;
    }
  }
end_ar_command:
  if( cmd.db!=pState->db ){
    sqlite3_close(cmd.db);
  }
  sqlite3_free(cmd.zSrcTable);

  return rc;
}
/* End of the ".archive" or ".ar" command logic
**********************************************************************************/
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */


/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int do_meta_command(char *zLine, ShellState *p){
  int h = 1;
  int nArg = 0;
  int n, c;
  int rc = 0;
  char *azArg[50];

#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( p->expert.pExpert ){
    expertFinish(p, 1, 0);
  }
#endif

  /* Parse the input line into tokens.
  */
  while( zLine[h] && nArg<ArraySize(azArg) ){
    while( IsSpace(zLine[h]) ){ h++; }
    if( zLine[h]==0 ) break;
    if( zLine[h]=='\'' || zLine[h]=='"' ){
4353
4354
4355
4356
4357
4358
4359

4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375







4376
4377
4378
4379
4380
4381
4382
  }

  /* Process the input line.
  */
  if( nArg==0 ) return 0; /* no tokens, no error */
  n = strlen30(azArg[0]);
  c = azArg[0][0];


#ifndef SQLITE_OMIT_AUTHORIZATION
  if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .auth ON|OFF\n");
      rc = 1;
      goto meta_command_exit;
    }
    open_db(p, 0);
    if( booleanValue(azArg[1]) ){
      sqlite3_set_authorizer(p->db, shellAuth, p);
    }else{
      sqlite3_set_authorizer(p->db, 0, 0);
    }
  }else
#endif








  if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
   || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
  ){
    const char *zDestFile = 0;
    const char *zDb = 0;
    sqlite3 *pDest;







>
















>
>
>
>
>
>
>







5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
  }

  /* Process the input line.
  */
  if( nArg==0 ) return 0; /* no tokens, no error */
  n = strlen30(azArg[0]);
  c = azArg[0][0];
  clearTempFile(p);

#ifndef SQLITE_OMIT_AUTHORIZATION
  if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .auth ON|OFF\n");
      rc = 1;
      goto meta_command_exit;
    }
    open_db(p, 0);
    if( booleanValue(azArg[1]) ){
      sqlite3_set_authorizer(p->db, shellAuth, p);
    }else{
      sqlite3_set_authorizer(p->db, 0, 0);
    }
  }else
#endif

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
  if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
    open_db(p, 0);
    rc = arDotCommand(p, azArg, nArg);
  }else
#endif

  if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
   || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
  ){
    const char *zDestFile = 0;
    const char *zDb = 0;
    sqlite3 *pDest;
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
  if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
    if( nArg==2 ){
      if( strcmp(azArg[1],"full")==0 ){
        p->autoEQP = AUTOEQP_full;
      }else if( strcmp(azArg[1],"trigger")==0 ){
        p->autoEQP = AUTOEQP_trigger;
      }else{
        p->autoEQP = booleanValue(azArg[1]);
      }
    }else{
      raw_printf(stderr, "Usage: .eqp off|on|trigger|full\n");
      rc = 1;
    }
  }else








|







5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
  if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
    if( nArg==2 ){
      if( strcmp(azArg[1],"full")==0 ){
        p->autoEQP = AUTOEQP_full;
      }else if( strcmp(azArg[1],"trigger")==0 ){
        p->autoEQP = AUTOEQP_trigger;
      }else{
        p->autoEQP = (u8)booleanValue(azArg[1]);
      }
    }else{
      raw_printf(stderr, "Usage: .eqp off|on|trigger|full\n");
      rc = 1;
    }
  }else

4680
4681
4682
4683
4684
4685
4686

4687
4688
4689
4690

4691
4692
4693
4694
4695
4696
4697
      p->autoExplain = 0;
    }else if( val==99 ){
      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
      p->autoExplain = 1;
    }
  }else


  if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
    open_db(p, 0);
    expertDotCommand(p, azArg, nArg);
  }else


  if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
    ShellState data;
    char *zErrMsg = 0;
    int doStats = 0;
    memcpy(&data, p, sizeof(data));
    data.showHeader = 0;







>




>







5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
      p->autoExplain = 0;
    }else if( val==99 ){
      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
      p->autoExplain = 1;
    }
  }else

#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
    open_db(p, 0);
    expertDotCommand(p, azArg, nArg);
  }else
#endif

  if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
    ShellState data;
    char *zErrMsg = 0;
    int doStats = 0;
    memcpy(&data, p, sizeof(data));
    data.showHeader = 0;
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .log FILENAME\n");
      rc = 1;
    }else{
      const char *zFile = azArg[1];
      output_file_close(p->pLog);
      p->pLog = output_file_open(zFile);
    }
  }else

  if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
    const char *zMode = nArg>=2 ? azArg[1] : "";
    int n2 = (int)strlen(zMode);
    int c2 = zMode[0];
    if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
      p->mode = MODE_Line;
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
      p->mode = MODE_Column;
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);







|





|







6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .log FILENAME\n");
      rc = 1;
    }else{
      const char *zFile = azArg[1];
      output_file_close(p->pLog);
      p->pLog = output_file_open(zFile, 0);
    }
  }else

  if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
    const char *zMode = nArg>=2 ? azArg[1] : "";
    int n2 = strlen30(zMode);
    int c2 = zMode[0];
    if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
      p->mode = MODE_Line;
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
      p->mode = MODE_Column;
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
5210
5211
5212
5213
5214
5215
5216

5217
5218
5219
5220
5221






5222
5223
5224
5225
5226
5227
5228
    /* Close the existing database */
    session_close_all(p);
    sqlite3_close(p->db);
    p->db = 0;
    p->zDbFilename = 0;
    sqlite3_free(p->zFreeOnClose);
    p->zFreeOnClose = 0;

    /* Check for command-line arguments */
    for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
      const char *z = azArg[iName];
      if( optionMatch(z,"new") ){
        newFlag = 1;






      }else if( z[0]=='-' ){
        utf8_printf(stderr, "unknown option: %s\n", z);
        rc = 1;
        goto meta_command_exit;
      }
    }
    /* If a filename is specified, try to open it first */







>





>
>
>
>
>
>







6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
    /* Close the existing database */
    session_close_all(p);
    sqlite3_close(p->db);
    p->db = 0;
    p->zDbFilename = 0;
    sqlite3_free(p->zFreeOnClose);
    p->zFreeOnClose = 0;
    p->openMode = SHELL_OPEN_UNSPEC;
    /* Check for command-line arguments */
    for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
      const char *z = azArg[iName];
      if( optionMatch(z,"new") ){
        newFlag = 1;
#ifdef SQLITE_HAVE_ZIP
      }else if( optionMatch(z, "zip") ){
        p->openMode = SHELL_OPEN_ZIPFILE;
#endif
      }else if( optionMatch(z, "append") ){
        p->openMode = SHELL_OPEN_APPENDVFS;
      }else if( z[0]=='-' ){
        utf8_printf(stderr, "unknown option: %s\n", z);
        rc = 1;
        goto meta_command_exit;
      }
    }
    /* If a filename is specified, try to open it first */
5241
5242
5243
5244
5245
5246
5247
5248
5249

5250
5251








5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267















5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
    if( p->db==0 ){
      /* As a fall-back open a TEMP database */
      p->zDbFilename = 0;
      open_db(p, 0);
    }
  }else

  if( c=='o'
   && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)

  ){
    const char *zFile = nArg>=2 ? azArg[1] : "stdout";








    if( nArg>2 ){
      utf8_printf(stderr, "Usage: .%s FILE\n", azArg[0]);
      rc = 1;
      goto meta_command_exit;
    }
    if( n>1 && strncmp(azArg[0], "once", n)==0 ){
      if( nArg<2 ){
        raw_printf(stderr, "Usage: .once FILE\n");
        rc = 1;
        goto meta_command_exit;
      }
      p->outCount = 2;
    }else{
      p->outCount = 0;
    }
    output_reset(p);















    if( zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      p->out = stdout;
#else
      p->out = popen(zFile + 1, "w");
      if( p->out==0 ){
        utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
        p->out = stdout;
        rc = 1;
      }else{
        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
#endif
    }else{
      p->out = output_file_open(zFile);
      if( p->out==0 ){
        if( strcmp(zFile,"off")!=0 ){
          utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
        }
        p->out = stdout;
        rc = 1;
      } else {







|
|
>


>
>
>
>
>
>
>
>

|





|








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
















|







6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
    if( p->db==0 ){
      /* As a fall-back open a TEMP database */
      p->zDbFilename = 0;
      open_db(p, 0);
    }
  }else

  if( (c=='o'
        && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
   || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
  ){
    const char *zFile = nArg>=2 ? azArg[1] : "stdout";
    int bTxtMode = 0;
    if( azArg[0][0]=='e' ){
      /* Transform the ".excel" command into ".once -x" */
      nArg = 2;
      azArg[0] = "once";
      zFile = azArg[1] = "-x";
      n = 4;
    }
    if( nArg>2 ){
      utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]);
      rc = 1;
      goto meta_command_exit;
    }
    if( n>1 && strncmp(azArg[0], "once", n)==0 ){
      if( nArg<2 ){
        raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n");
        rc = 1;
        goto meta_command_exit;
      }
      p->outCount = 2;
    }else{
      p->outCount = 0;
    }
    output_reset(p);
    if( zFile[0]=='-' && zFile[1]=='-' ) zFile++;
    if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){
      p->doXdgOpen = 1;
      outputModePush(p);
      if( zFile[1]=='x' ){
        newTempFile(p, "csv");
        p->mode = MODE_Csv;
        sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
      }else{
        newTempFile(p, "txt");
        bTxtMode = 1;
      }
      zFile = p->zTempFile;
    }
    if( zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      p->out = stdout;
#else
      p->out = popen(zFile + 1, "w");
      if( p->out==0 ){
        utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
        p->out = stdout;
        rc = 1;
      }else{
        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
      }
#endif
    }else{
      p->out = output_file_open(zFile, bTxtMode);
      if( p->out==0 ){
        if( strcmp(zFile,"off")!=0 ){
          utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
        }
        p->out = stdout;
        rc = 1;
      } else {
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
    }
    sqlite3_close(pSrc);
  }else


  if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
    if( nArg==2 ){
      p->scanstatsOn = booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
#endif
    }else{
      raw_printf(stderr, "Usage: .scanstats on|off\n");
      rc = 1;
    }







|







6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
    }
    sqlite3_close(pSrc);
  }else


  if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
    if( nArg==2 ){
      p->scanstatsOn = (u8)booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
#endif
    }else{
      raw_printf(stderr, "Usage: .scanstats on|off\n");
      rc = 1;
    }
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
    raw_printf(p->out, "\n");
    utf8_printf(p->out, "%12.12s: %s\n", "filename",
                p->zDbFilename ? p->zDbFilename : "");
  }else

  if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
    if( nArg==2 ){
      p->statsOn = booleanValue(azArg[1]);
    }else if( nArg==1 ){
      display_stats(p->db, p, 0);
    }else{
      raw_printf(stderr, "Usage: .stats ?on|off?\n");
      rc = 1;
    }
  }else







|







7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
    raw_printf(p->out, "\n");
    utf8_printf(p->out, "%12.12s: %s\n", "filename",
                p->zDbFilename ? p->zDbFilename : "");
  }else

  if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
    if( nArg==2 ){
      p->statsOn = (u8)booleanValue(azArg[1]);
    }else if( nArg==1 ){
      display_stats(p->db, p, 0);
    }else{
      raw_printf(stderr, "Usage: .stats ?on|off?\n");
      rc = 1;
    }
  }else
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
    for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
    sqlite3_free(azResult);
  }else

  /* Begin redirecting output to the file "testcase-out.txt" */
  if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
    output_reset(p);
    p->out = output_file_open("testcase-out.txt");
    if( p->out==0 ){
      raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
    }
    if( nArg>=2 ){
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
    }else{
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");







|







7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
    for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
    sqlite3_free(azResult);
  }else

  /* Begin redirecting output to the file "testcase-out.txt" */
  if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
    output_reset(p);
    p->out = output_file_open("testcase-out.txt", 0);
    if( p->out==0 ){
      raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
    }
    if( nArg>=2 ){
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
    }else{
      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
    open_db(p, 0);
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .trace FILE|off\n");
      rc = 1;
      goto meta_command_exit;
    }
    output_file_close(p->traceOut);
    p->traceOut = output_file_open(azArg[1]);
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
    if( p->traceOut==0 ){
      sqlite3_trace_v2(p->db, 0, 0, 0);
    }else{
      sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
    }
#endif







|







7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
    open_db(p, 0);
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .trace FILE|off\n");
      rc = 1;
      goto meta_command_exit;
    }
    output_file_close(p->traceOut);
    p->traceOut = output_file_open(azArg[1], 0);
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
    if( p->traceOut==0 ){
      sqlite3_trace_v2(p->db, 0, 0, 0);
    }else{
      sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
    }
#endif
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
    open_db(p, 0);
    if( strcmp(azArg[1],"login")==0 ){
      if( nArg!=4 ){
        raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
        rc = 1;
        goto meta_command_exit;
      }
      rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
                                    (int)strlen(azArg[3]));
      if( rc ){
        utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
        rc = 1;
      }
    }else if( strcmp(azArg[1],"add")==0 ){
      if( nArg!=5 ){
        raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
        rc = 1;
        goto meta_command_exit;
      }
      rc = sqlite3_user_add(p->db, azArg[2],
                            azArg[3], (int)strlen(azArg[3]),
                            booleanValue(azArg[4]));
      if( rc ){
        raw_printf(stderr, "User-Add failed: %d\n", rc);
        rc = 1;
      }
    }else if( strcmp(azArg[1],"edit")==0 ){
      if( nArg!=5 ){
        raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
        rc = 1;
        goto meta_command_exit;
      }
      rc = sqlite3_user_change(p->db, azArg[2],
                              azArg[3], (int)strlen(azArg[3]),
                              booleanValue(azArg[4]));
      if( rc ){
        raw_printf(stderr, "User-Edit failed: %d\n", rc);
        rc = 1;
      }
    }else if( strcmp(azArg[1],"delete")==0 ){
      if( nArg!=3 ){







|
<










|
<











|
<







7486
7487
7488
7489
7490
7491
7492
7493

7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504

7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516

7517
7518
7519
7520
7521
7522
7523
    open_db(p, 0);
    if( strcmp(azArg[1],"login")==0 ){
      if( nArg!=4 ){
        raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
        rc = 1;
        goto meta_command_exit;
      }
      rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3]));

      if( rc ){
        utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
        rc = 1;
      }
    }else if( strcmp(azArg[1],"add")==0 ){
      if( nArg!=5 ){
        raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
        rc = 1;
        goto meta_command_exit;
      }
      rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),

                            booleanValue(azArg[4]));
      if( rc ){
        raw_printf(stderr, "User-Add failed: %d\n", rc);
        rc = 1;
      }
    }else if( strcmp(azArg[1],"edit")==0 ){
      if( nArg!=5 ){
        raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
        rc = 1;
        goto meta_command_exit;
      }
      rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),

                              booleanValue(azArg[4]));
      if( rc ){
        raw_printf(stderr, "User-Edit failed: %d\n", rc);
        rc = 1;
      }
    }else if( strcmp(azArg[1],"delete")==0 ){
      if( nArg!=3 ){
6438
6439
6440
6441
6442
6443
6444














6445
6446
6447
6448
6449
6450
6451
    }
  }else
#endif /* SQLITE_USER_AUTHENTICATION */

  if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
    utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
        sqlite3_libversion(), sqlite3_sourceid());














  }else

  if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
    const char *zDbName = nArg==2 ? azArg[1] : "main";
    sqlite3_vfs *pVfs = 0;
    if( p->db ){
      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);







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







7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
    }
  }else
#endif /* SQLITE_USER_AUTHENTICATION */

  if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
    utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
        sqlite3_libversion(), sqlite3_sourceid());
#if SQLITE_HAVE_ZLIB
    utf8_printf(p->out, "zlib version %s\n", zlibVersion());
#endif
#define CTIMEOPT_VAL_(opt) #opt
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
#if defined(__clang__) && defined(__clang_major__)
    utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
                    CTIMEOPT_VAL(__clang_minor__) "."
                    CTIMEOPT_VAL(__clang_patchlevel__) "\n");
#elif defined(_MSC_VER)
    utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
#elif defined(__GNUC__) && defined(__VERSION__)
    utf8_printf(p->out, "gcc-" __VERSION__ "\n");
#endif
  }else

  if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
    const char *zDbName = nArg==2 ? azArg[1] : "main";
    sqlite3_vfs *pVfs = 0;
    if( p->db ){
      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
6563
6564
6565
6566
6567
6568
6569










6570
6571
6572
6573
6574
6575
6576
  if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
         && _all_whitespace(&zLine[2]) ){
    return 1;  /* SQL Server */
  }
  return 0;
}











/*
** Return true if zSql is a complete SQL statement.  Return false if it
** ends in the middle of a string literal or C-style comment.
*/
static int line_is_complete(char *zSql, int nSql){
  int rc;
  if( zSql==0 ) return 1;







>
>
>
>
>
>
>
>
>
>







7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
  if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
         && _all_whitespace(&zLine[2]) ){
    return 1;  /* SQL Server */
  }
  return 0;
}

/*
** We need a default sqlite3_complete() implementation to use in case
** the shell is compiled with SQLITE_OMIT_COMPLETE.  The default assumes
** any arbitrary text is a complete SQL statement.  This is not very
** user-friendly, but it does seem to work.
*/
#ifdef SQLITE_OMIT_COMPLETE
int sqlite3_complete(const char *zSql){ return 1; }
#endif

/*
** Return true if zSql is a complete SQL statement.  Return false if it
** ends in the middle of a string literal or C-style comment.
*/
static int line_is_complete(char *zSql, int nSql){
  int rc;
  if( zSql==0 ) return 1;
6693
6694
6695
6696
6697
6698
6699


6700
6701
6702
6703
6704
6705
6706
    if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
                && sqlite3_complete(zSql) ){
      errCnt += runOneSqlLine(p, zSql, in, startline);
      nSql = 0;
      if( p->outCount ){
        output_reset(p);
        p->outCount = 0;


      }
    }else if( nSql && _all_whitespace(zSql) ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
      nSql = 0;
    }
  }
  if( nSql && !_all_whitespace(zSql) ){







>
>







7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
    if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
                && sqlite3_complete(zSql) ){
      errCnt += runOneSqlLine(p, zSql, in, startline);
      nSql = 0;
      if( p->outCount ){
        output_reset(p);
        p->outCount = 0;
      }else{
        clearTempFile(p);
      }
    }else if( nSql && _all_whitespace(zSql) ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
      nSql = 0;
    }
  }
  if( nSql && !_all_whitespace(zSql) ){
7086
7087
7088
7089
7090
7091
7092






7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104

7105
7106
7107
7108
7109
7110
7111
      sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
      if( pVfs ){
        sqlite3_vfs_register(pVfs, 1);
      }else{
        utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
        exit(1);
      }






    }
  }
  if( data.zDbFilename==0 ){
#ifndef SQLITE_OMIT_MEMORYDB
    data.zDbFilename = ":memory:";
    warnInmemoryDb = argc==1;
#else
    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
    return 1;
#endif
  }
  data.out = stdout;


  /* Go ahead and open the database file if it already exists.  If the
  ** file does not exist, delay opening it.  This prevents empty database
  ** files from being created if a user mistypes the database name argument
  ** to the sqlite command-line tool.
  */
  if( access(data.zDbFilename, 0)==0 ){







>
>
>
>
>
>












>







8211
8212
8213
8214
8215
8216
8217
8218
8219
8220
8221
8222
8223
8224
8225
8226
8227
8228
8229
8230
8231
8232
8233
8234
8235
8236
8237
8238
8239
8240
8241
8242
8243
      sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
      if( pVfs ){
        sqlite3_vfs_register(pVfs, 1);
      }else{
        utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
        exit(1);
      }
#ifdef SQLITE_HAVE_ZIP
    }else if( strcmp(z,"-zip")==0 ){
      data.openMode = SHELL_OPEN_ZIPFILE;
#endif
    }else if( strcmp(z,"-append")==0 ){
      data.openMode = SHELL_OPEN_APPENDVFS;
    }
  }
  if( data.zDbFilename==0 ){
#ifndef SQLITE_OMIT_MEMORYDB
    data.zDbFilename = ":memory:";
    warnInmemoryDb = argc==1;
#else
    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
    return 1;
#endif
  }
  data.out = stdout;
  sqlite3_appendvfs_init(0,0,0);

  /* Go ahead and open the database file if it already exists.  If the
  ** file does not exist, delay opening it.  This prevents empty database
  ** files from being created if a user mistypes the database name argument
  ** to the sqlite command-line tool.
  */
  if( access(data.zDbFilename, 0)==0 ){
7138
7139
7140
7141
7142
7143
7144






7145
7146
7147
7148
7149
7150
7151
    }else if( strcmp(z,"-line")==0 ){
      data.mode = MODE_Line;
    }else if( strcmp(z,"-column")==0 ){
      data.mode = MODE_Column;
    }else if( strcmp(z,"-csv")==0 ){
      data.mode = MODE_Csv;
      memcpy(data.colSeparator,",",2);






    }else if( strcmp(z,"-ascii")==0 ){
      data.mode = MODE_Ascii;
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
                       SEP_Unit);
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
                       SEP_Record);
    }else if( strcmp(z,"-separator")==0 ){







>
>
>
>
>
>







8270
8271
8272
8273
8274
8275
8276
8277
8278
8279
8280
8281
8282
8283
8284
8285
8286
8287
8288
8289
    }else if( strcmp(z,"-line")==0 ){
      data.mode = MODE_Line;
    }else if( strcmp(z,"-column")==0 ){
      data.mode = MODE_Column;
    }else if( strcmp(z,"-csv")==0 ){
      data.mode = MODE_Csv;
      memcpy(data.colSeparator,",",2);
#ifdef SQLITE_HAVE_ZIP
    }else if( strcmp(z,"-zip")==0 ){
      data.openMode = SHELL_OPEN_ZIPFILE;
#endif
    }else if( strcmp(z,"-append")==0 ){
      data.openMode = SHELL_OPEN_APPENDVFS;
    }else if( strcmp(z,"-ascii")==0 ){
      data.mode = MODE_Ascii;
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
                       SEP_Unit);
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
                       SEP_Record);
    }else if( strcmp(z,"-separator")==0 ){
7302
7303
7304
7305
7306
7307
7308



7309
7310
7311
7312
7313
7314
  set_table_name(&data, 0);
  if( data.db ){
    session_close_all(&data);
    sqlite3_close(data.db);
  }
  sqlite3_free(data.zFreeOnClose);
  find_home_dir(1);



#if !SQLITE_SHELL_IS_UTF8
  for(i=0; i<argc; i++) sqlite3_free(argv[i]);
  sqlite3_free(argv);
#endif
  return rc;
}







>
>
>






8440
8441
8442
8443
8444
8445
8446
8447
8448
8449
8450
8451
8452
8453
8454
8455
  set_table_name(&data, 0);
  if( data.db ){
    session_close_all(&data);
    sqlite3_close(data.db);
  }
  sqlite3_free(data.zFreeOnClose);
  find_home_dir(1);
  output_reset(&data);
  data.doXdgOpen = 0;
  clearTempFile(&data);
#if !SQLITE_SHELL_IS_UTF8
  for(i=0; i<argc; i++) sqlite3_free(argv[i]);
  sqlite3_free(argv);
#endif
  return rc;
}
Changes to src/sqlite.h.in.
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
#define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
#define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
#define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR          (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH       (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH       (SQLITE_CANTOPEN | (4<<8))
#define SQLITE_CANTOPEN_DIRTYWAL       (SQLITE_CANTOPEN | (5<<8))
#define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
#define SQLITE_READONLY_CANTINIT       (SQLITE_READONLY | (5<<8))
#define SQLITE_READONLY_DIRECTORY      (SQLITE_READONLY | (6<<8))







<







506
507
508
509
510
511
512

513
514
515
516
517
518
519
#define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
#define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
#define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR          (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH       (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH       (SQLITE_CANTOPEN | (4<<8))

#define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
#define SQLITE_READONLY_CANTINIT       (SQLITE_READONLY | (5<<8))
#define SQLITE_READONLY_DIRECTORY      (SQLITE_READONLY | (6<<8))
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
   void(*xProfile)(void*,const char*,sqlite3_uint64), void*);

/*
** CAPI3REF: SQL Trace Event Codes
** KEYWORDS: SQLITE_TRACE
**
** These constants identify classes of events that can be monitored
** using the [sqlite3_trace_v2()] tracing logic.  The third argument
** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
** the following constants.  ^The first argument to the trace callback
** is one of the following constants.
**
** New tracing constants may be added in future releases.
**
** ^A trace callback has four arguments: xCallback(T,C,P,X).
** ^The T argument is one of the integer type codes above.







|
|







2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
   void(*xProfile)(void*,const char*,sqlite3_uint64), void*);

/*
** CAPI3REF: SQL Trace Event Codes
** KEYWORDS: SQLITE_TRACE
**
** These constants identify classes of events that can be monitored
** using the [sqlite3_trace_v2()] tracing logic.  The M argument
** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of
** the following constants.  ^The first argument to the trace callback
** is one of the following constants.
**
** New tracing constants may be added in future releases.
**
** ^A trace callback has four arguments: xCallback(T,C,P,X).
** ^The T argument is one of the integer type codes above.
3656
3657
3658
3659
3660
3661
3662

3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
** a schema change, on the first  [sqlite3_step()] call following any change
** to the [sqlite3_bind_text | bindings] of that [parameter]. 
** ^The specific value of WHERE-clause [parameter] might influence the 
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
** </li>

**
** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
** the extra prepFlags parameter, which is a bit array consisting of zero or
** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags.  ^The
** sqlite3_prepare_v2() interface works exactly the same as
** sqlite3_prepare_v3() with a zero prepFlags parameter.
** </ol>
*/
int sqlite3_prepare(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */







>






<







3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668

3669
3670
3671
3672
3673
3674
3675
** a schema change, on the first  [sqlite3_step()] call following any change
** to the [sqlite3_bind_text | bindings] of that [parameter]. 
** ^The specific value of WHERE-clause [parameter] might influence the 
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
** </li>
** </ol>
**
** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
** the extra prepFlags parameter, which is a bit array consisting of zero or
** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags.  ^The
** sqlite3_prepare_v2() interface works exactly the same as
** sqlite3_prepare_v3() with a zero prepFlags parameter.

*/
int sqlite3_prepare(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
4795
4796
4797
4798
4799
4800
4801



4802
4803
4804
4805
4806
4807
4808
** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
** TEXT in bytes
** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
** datatype of the value
** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value



** </table></blockquote>
**
** <b>Details:</b>
**
** These routines extract type, size, and content information from
** [protected sqlite3_value] objects.  Protected sqlite3_value objects
** are used to pass parameter information into implementation of







>
>
>







4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
** TEXT in bytes
** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
** datatype of the value
** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
** <tr><td><b>sqlite3_value_nochange&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
** against a virtual table.
** </table></blockquote>
**
** <b>Details:</b>
**
** These routines extract type, size, and content information from
** [protected sqlite3_value] objects.  Protected sqlite3_value objects
** are used to pass parameter information into implementation of
4842
4843
4844
4845
4846
4847
4848













4849
4850
4851
4852
4853
4854
4855
** ^(The sqlite3_value_numeric_type() interface attempts to apply
** numeric affinity to the value.  This means that an attempt is
** made to convert the value to an integer or floating point.  If
** such a conversion is possible without loss of information (in other
** words, if the value is a string that looks like a number)
** then the conversion is performed.  Otherwise no conversion occurs.
** The [SQLITE_INTEGER | datatype] after conversion is returned.)^













**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
** or [sqlite3_value_text16()].
**







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







4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
** ^(The sqlite3_value_numeric_type() interface attempts to apply
** numeric affinity to the value.  This means that an attempt is
** made to convert the value to an integer or floating point.  If
** such a conversion is possible without loss of information (in other
** words, if the value is a string that looks like a number)
** then the conversion is performed.  Otherwise no conversion occurs.
** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
**
** ^Within the [xUpdate] method of a [virtual table], the
** sqlite3_value_nochange(X) interface returns true if and only if
** the column corresponding to X is unchanged by the UPDATE operation
** that the xUpdate method call was invoked to implement and if
** and the prior [xColumn] method call that was invoked to extracted
** the value for that column returned without setting a result (probably
** because it queried [sqlite3_vtab_nochange()] and found that the column
** was unchanging).  ^Within an [xUpdate] method, any value for which
** sqlite3_value_nochange(X) is true will in all other respects appear
** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
** than within an [xUpdate] method call for an UPDATE statement, then
** the return value is arbitrary and meaningless.
**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
** or [sqlite3_value_text16()].
**
4865
4866
4867
4868
4869
4870
4871

4872
4873
4874
4875
4876
4877
4878
const void *sqlite3_value_text16(sqlite3_value*);
const void *sqlite3_value_text16le(sqlite3_value*);
const void *sqlite3_value_text16be(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
int sqlite3_value_bytes16(sqlite3_value*);
int sqlite3_value_type(sqlite3_value*);
int sqlite3_value_numeric_type(sqlite3_value*);


/*
** CAPI3REF: Finding The Subtype Of SQL Values
** METHOD: sqlite3_value
**
** The sqlite3_value_subtype(V) function returns the subtype for
** an [application-defined SQL function] argument V.  The subtype







>







4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
const void *sqlite3_value_text16(sqlite3_value*);
const void *sqlite3_value_text16le(sqlite3_value*);
const void *sqlite3_value_text16be(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
int sqlite3_value_bytes16(sqlite3_value*);
int sqlite3_value_type(sqlite3_value*);
int sqlite3_value_numeric_type(sqlite3_value*);
int sqlite3_value_nochange(sqlite3_value*);

/*
** CAPI3REF: Finding The Subtype Of SQL Values
** METHOD: sqlite3_value
**
** The sqlite3_value_subtype(V) function returns the subtype for
** an [application-defined SQL function] argument V.  The subtype
8293
8294
8295
8296
8297
8298
8299



















8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
int sqlite3_vtab_on_conflict(sqlite3 *);




















/*
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
**
** This function may only be called from within a call to the [xBestIndex]
** method of a [virtual table implementation]. 
**
** The first argument must be the sqlite3_index_info object that is the
** first parameter to the xBestIndex() method. The second argument must be
** an index into the aConstraint[] array belonging to the sqlite3_index_info
** structure passed to xBestIndex. This function returns a pointer to a buffer 
** containing the name of the collation sequence for the corresponding
** constraint.







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




|







8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
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
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
int sqlite3_vtab_on_conflict(sqlite3 *);

/*
** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
**
** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
** method of a [virtual table], then it returns true if and only if the
** column is being fetched as part of an UPDATE operation during which the
** column value will not change.  Applications might use this to substitute
** a lighter-weight value to return that the corresponding [xUpdate] method
** understands as a "no-change" value.
**
** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
** the column is not changed by the UPDATE statement, they the xColumn
** method can optionally return without setting a result, without calling
** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
** In that case, [sqlite3_value_nochange(X)] will return true for the
** same column in the [xUpdate] method.
*/
int sqlite3_vtab_nochange(sqlite3_context*);

/*
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
**
** This function may only be called from within a call to the [xBestIndex]
** method of a [virtual table]. 
**
** The first argument must be the sqlite3_index_info object that is the
** first parameter to the xBestIndex() method. The second argument must be
** an index into the aConstraint[] array belonging to the sqlite3_index_info
** structure passed to xBestIndex. This function returns a pointer to a buffer 
** containing the name of the collation sequence for the corresponding
** constraint.
Changes to src/sqlite3ext.h.
288
289
290
291
292
293
294



295
296
297
298
299
300
301
  int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
                    sqlite3_stmt**,const char**);
  int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
                      sqlite3_stmt**,const void**);
  int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
  void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
  void *(*value_pointer)(sqlite3_value*,const char*);



};

/*
** This is the function signature used for all extension entry points.  It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(







>
>
>







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
                    sqlite3_stmt**,const char**);
  int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
                      sqlite3_stmt**,const void**);
  int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
  void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
  void *(*value_pointer)(sqlite3_value*,const char*);
  int (*vtab_nochange)(sqlite3_context*);
  int (*value_nochange)(sqlite3_value*);
  const char *(*vtab_collation)(sqlite3_index_info*,int);
};

/*
** This is the function signature used for all extension entry points.  It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
554
555
556
557
558
559
560




561
562
563
564
565
566
567
#define sqlite3_set_last_insert_rowid  sqlite3_api->set_last_insert_rowid
/* Version 3.20.0 and later */
#define sqlite3_prepare_v3             sqlite3_api->prepare_v3
#define sqlite3_prepare16_v3           sqlite3_api->prepare16_v3
#define sqlite3_bind_pointer           sqlite3_api->bind_pointer
#define sqlite3_result_pointer         sqlite3_api->result_pointer
#define sqlite3_value_pointer          sqlite3_api->value_pointer




#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */

#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
  /* This case when the file really is being compiled as a loadable 
  ** extension */
# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;







>
>
>
>







557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
#define sqlite3_set_last_insert_rowid  sqlite3_api->set_last_insert_rowid
/* Version 3.20.0 and later */
#define sqlite3_prepare_v3             sqlite3_api->prepare_v3
#define sqlite3_prepare16_v3           sqlite3_api->prepare16_v3
#define sqlite3_bind_pointer           sqlite3_api->bind_pointer
#define sqlite3_result_pointer         sqlite3_api->result_pointer
#define sqlite3_value_pointer          sqlite3_api->value_pointer
/* Version 3.22.0 and later */
#define sqlite3_vtab_nochange          sqlite3_api->vtab_nochange
#define sqlite3_value_nochange         sqlite3_api->value_nochange
#define sqlite3_vtab_collation         sqlite3_api->vtab_collation
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */

#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
  /* This case when the file really is being compiled as a loadable 
  ** extension */
# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;
Changes to src/sqliteInt.h.
3114
3115
3116
3117
3118
3119
3120

3121
3122
3123
3124
3125
3126
3127
#define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ        0x02    /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE     0x08    /* OP_Open should use BTREE_FORDELETE */
#define OPFLAG_P2ISREG       0x10    /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */
#define OPFLAG_SAVEPOSITION  0x02    /* OP_Delete/Insert: save cursor pos */
#define OPFLAG_AUXDELETE     0x04    /* OP_Delete: index in a DELETE op */


/*
 * Each trigger present in the database schema is stored as an instance of
 * struct Trigger.
 *
 * Pointers to instances of struct Trigger are stored in two ways.
 * 1. In the "trigHash" hash table (part of the sqlite3* that represents the







>







3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
#define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ        0x02    /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE     0x08    /* OP_Open should use BTREE_FORDELETE */
#define OPFLAG_P2ISREG       0x10    /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */
#define OPFLAG_SAVEPOSITION  0x02    /* OP_Delete/Insert: save cursor pos */
#define OPFLAG_AUXDELETE     0x04    /* OP_Delete: index in a DELETE op */
#define OPFLAG_NOCHNG_MAGIC  0x6d    /* OP_MakeRecord: serialtype 10 is ok */

/*
 * Each trigger present in the database schema is stored as an instance of
 * struct Trigger.
 *
 * Pointers to instances of struct Trigger are stored in two ways.
 * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
Changes to src/tclsqlite.c.
60
61
62
63
64
65
66

67

68
69
70
71
72
73
74

/* Used to get the current process ID */
#if !defined(_WIN32)
# include <unistd.h>
# define GETPID getpid
#elif !defined(_WIN32_WCE)
# ifndef SQLITE_AMALGAMATION

#  define WIN32_LEAN_AND_MEAN

#  include <windows.h>
# endif
# define GETPID (int)GetCurrentProcessId
#endif

/*
 * Windows needs to know which symbols to export.  Unix does not.







>
|
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

/* Used to get the current process ID */
#if !defined(_WIN32)
# include <unistd.h>
# define GETPID getpid
#elif !defined(_WIN32_WCE)
# ifndef SQLITE_AMALGAMATION
#  ifndef WIN32_LEAN_AND_MEAN
#   define WIN32_LEAN_AND_MEAN
#  endif
#  include <windows.h>
# endif
# define GETPID (int)GetCurrentProcessId
#endif

/*
 * Windows needs to know which symbols to export.  Unix does not.
Changes to src/test1.c.
6956
6957
6958
6959
6960
6961
6962



6963
6964
6965
6966
6967
6968
6969
  extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*);



  static const struct {
    const char *zExtName;
    int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
  } aExtension[] = {
    { "amatch",                sqlite3_amatch_init               },
    { "carray",                sqlite3_carray_init               },
    { "closure",               sqlite3_closure_init              },







>
>
>







6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
  extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
#ifdef SQLITE_HAVE_ZLIB
  extern int sqlite3_zipfile_init(sqlite3*,char**,const sqlite3_api_routines*);
#endif
  static const struct {
    const char *zExtName;
    int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
  } aExtension[] = {
    { "amatch",                sqlite3_amatch_init               },
    { "carray",                sqlite3_carray_init               },
    { "closure",               sqlite3_closure_init              },
6977
6978
6979
6980
6981
6982
6983



6984
6985
6986
6987
6988
6989
6990
    { "regexp",                sqlite3_regexp_init               },
    { "remember",              sqlite3_remember_init             },
    { "series",                sqlite3_series_init               },
    { "spellfix",              sqlite3_spellfix_init             },
    { "totype",                sqlite3_totype_init               },
    { "unionvtab",             sqlite3_unionvtab_init            },
    { "wholenumber",           sqlite3_wholenumber_init          },



  };
  sqlite3 *db;
  const char *zName;
  int i, j, rc;
  char *zErrMsg = 0;
  if( objc<3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB NAME ...");







>
>
>







6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
    { "regexp",                sqlite3_regexp_init               },
    { "remember",              sqlite3_remember_init             },
    { "series",                sqlite3_series_init               },
    { "spellfix",              sqlite3_spellfix_init             },
    { "totype",                sqlite3_totype_init               },
    { "unionvtab",             sqlite3_unionvtab_init            },
    { "wholenumber",           sqlite3_wholenumber_init          },
#ifdef SQLITE_HAVE_ZLIB
    { "zipfile",               sqlite3_zipfile_init              },
#endif
  };
  sqlite3 *db;
  const char *zName;
  int i, j, rc;
  char *zErrMsg = 0;
  if( objc<3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB NAME ...");
Changes to src/test_windirent.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains code to implement most of the opendir() family of
** POSIX functions on Win32 using the MSVCRT.
*/

#if defined(_WIN32) && defined(_MSC_VER)

#include "test_windirent.h"

/*
** Implementation of the POSIX getenv() function using the Win32 API.
** This function is not thread-safe.
*/
const char *windirent_getenv(







<







10
11
12
13
14
15
16

17
18
19
20
21
22
23
**
*************************************************************************
** This file contains code to implement most of the opendir() family of
** POSIX functions on Win32 using the MSVCRT.
*/

#if defined(_WIN32) && defined(_MSC_VER)

#include "test_windirent.h"

/*
** Implementation of the POSIX getenv() function using the Win32 API.
** This function is not thread-safe.
*/
const char *windirent_getenv(
Changes to src/test_windirent.h.
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
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains declarations for most of the opendir() family of
** POSIX functions on Win32 using the MSVCRT.
*/

#if defined(_WIN32) && defined(_MSC_VER)


/*
** We need several data types from the Windows SDK header.
*/


#define WIN32_LEAN_AND_MEAN


#include "windows.h"

/*
** We need several support functions from the SQLite core.
*/

#include "sqlite3.h"

/*
** We need several things from the ANSI and MSVCRT headers.
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <io.h>
#include <limits.h>




























/*
** We may need to provide the "ino_t" type.
*/

#ifndef INO_T_DEFINED
  #define INO_T_DEFINED







|
>





>

>
>

















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







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
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains declarations for most of the opendir() family of
** POSIX functions on Win32 using the MSVCRT.
*/

#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
#define SQLITE_WINDIRENT_H

/*
** We need several data types from the Windows SDK header.
*/

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include "windows.h"

/*
** We need several support functions from the SQLite core.
*/

#include "sqlite3.h"

/*
** We need several things from the ANSI and MSVCRT headers.
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <io.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

/*
** We may need several defines that should have been in "sys/stat.h".
*/

#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#endif

#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif

#ifndef S_ISLNK
#define S_ISLNK(mode) (0)
#endif

/*
** We may need to provide the "mode_t" type.
*/

#ifndef MODE_T_DEFINED
  #define MODE_T_DEFINED
  typedef unsigned short mode_t;
#endif

/*
** We may need to provide the "ino_t" type.
*/

#ifndef INO_T_DEFINED
  #define INO_T_DEFINED
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
#  define BAD_INTPTR_T ((intptr_t)(-1))
#endif

/*
** We need to provide the necessary structures and related types.
*/

typedef struct DIRENT DIRENT;

typedef struct DIR DIR;
typedef DIRENT *LPDIRENT;
typedef DIR *LPDIR;

struct DIRENT {
  ino_t d_ino;               /* Sequence number, do not use. */
  unsigned d_attributes;     /* Win32 file attributes. */
  char d_name[NAME_MAX + 1]; /* Name within the directory. */
};






struct DIR {
  intptr_t d_handle; /* Value returned by "_findfirst". */
  DIRENT d_first;    /* DIRENT constructed based on "_findfirst". */
  DIRENT d_next;     /* DIRENT constructed based on "_findnext". */
};


/*
** Provide a macro, for use by the implementation, to determine if a
** particular directory entry should be skipped over when searching for
** the next directory entry that should be returned by the readdir() or
** readdir_r() functions.
*/







|
>
|

<
<





>

>
>
>
>





>







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
#  define BAD_INTPTR_T ((intptr_t)(-1))
#endif

/*
** We need to provide the necessary structures and related types.
*/

#ifndef DIRENT_DEFINED
#define DIRENT_DEFINED
typedef struct DIRENT DIRENT;
typedef DIRENT *LPDIRENT;


struct DIRENT {
  ino_t d_ino;               /* Sequence number, do not use. */
  unsigned d_attributes;     /* Win32 file attributes. */
  char d_name[NAME_MAX + 1]; /* Name within the directory. */
};
#endif

#ifndef DIR_DEFINED
#define DIR_DEFINED
typedef struct DIR DIR;
typedef DIR *LPDIR;
struct DIR {
  intptr_t d_handle; /* Value returned by "_findfirst". */
  DIRENT d_first;    /* DIRENT constructed based on "_findfirst". */
  DIRENT d_next;     /* DIRENT constructed based on "_findnext". */
};
#endif

/*
** Provide a macro, for use by the implementation, to determine if a
** particular directory entry should be skipped over when searching for
** the next directory entry that should be returned by the readdir() or
** readdir_r() functions.
*/
Changes to src/tokenize.c.
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
      if( lastTokenParsed==TK_SEMI ){
        tokenType = 0;
      }else if( lastTokenParsed==0 ){
        break;
      }else{
        tokenType = TK_SEMI;
      }
      zSql -= n;
    }
    if( tokenType>=TK_SPACE ){
      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
      if( db->u1.isInterrupted ){
        pParse->rc = SQLITE_INTERRUPT;
        break;
      }







|







522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
      if( lastTokenParsed==TK_SEMI ){
        tokenType = 0;
      }else if( lastTokenParsed==0 ){
        break;
      }else{
        tokenType = TK_SEMI;
      }
      n = 0;
    }
    if( tokenType>=TK_SPACE ){
      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
      if( db->u1.isInterrupted ){
        pParse->rc = SQLITE_INTERRUPT;
        break;
      }
Changes to src/update.c.
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830

831
832
833
834
835
836
837
  int regRec;                     /* Register in which to assemble record */
  int regRowid;                   /* Register for ephem table rowid */
  int iCsr = pSrc->a[0].iCursor;  /* Cursor used for virtual table scan */
  int aDummy[2];                  /* Unused arg for sqlite3WhereOkOnePass() */
  int bOnePass;                   /* True to use onepass strategy */
  int addr;                       /* Address of OP_OpenEphemeral */

  /* Allocate nArg registers to martial the arguments to VUpdate. Then
  ** create and open the ephemeral table in which the records created from
  ** these arguments will be temporarily stored. */
  assert( v );
  ephemTab = pParse->nTab++;
  addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
  regArg = pParse->nMem + 1;
  pParse->nMem += nArg;
  regRec = ++pParse->nMem;
  regRowid = ++pParse->nMem;

  /* Start scanning the virtual table */
  pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
  if( pWInfo==0 ) return;

  /* Populate the argument registers. */
  for(i=0; i<pTab->nCol; i++){
    if( aXRef[i]>=0 ){
      sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
    }else{
      sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);

    }
  }
  if( HasRowid(pTab) ){
    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
    if( pRowid ){
      sqlite3ExprCode(pParse, pRowid, regArg+1);
    }else{







|




















>







803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  int regRec;                     /* Register in which to assemble record */
  int regRowid;                   /* Register for ephem table rowid */
  int iCsr = pSrc->a[0].iCursor;  /* Cursor used for virtual table scan */
  int aDummy[2];                  /* Unused arg for sqlite3WhereOkOnePass() */
  int bOnePass;                   /* True to use onepass strategy */
  int addr;                       /* Address of OP_OpenEphemeral */

  /* Allocate nArg registers in which to gather the arguments for VUpdate. Then
  ** create and open the ephemeral table in which the records created from
  ** these arguments will be temporarily stored. */
  assert( v );
  ephemTab = pParse->nTab++;
  addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
  regArg = pParse->nMem + 1;
  pParse->nMem += nArg;
  regRec = ++pParse->nMem;
  regRowid = ++pParse->nMem;

  /* Start scanning the virtual table */
  pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
  if( pWInfo==0 ) return;

  /* Populate the argument registers. */
  for(i=0; i<pTab->nCol; i++){
    if( aXRef[i]>=0 ){
      sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
    }else{
      sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
      sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */
    }
  }
  if( HasRowid(pTab) ){
    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
    if( pRowid ){
      sqlite3ExprCode(pParse, pRowid, regArg+1);
    }else{
858
859
860
861
862
863
864





865
866
867
868
869
870
871
    if( sqlite3IsToplevel(pParse) ){
      pParse->isMultiWrite = 0;
    }
  }else{
    /* Create a record from the argument register contents and insert it into
    ** the ephemeral table. */
    sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);





    sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
  }


  if( bOnePass==0 ){
    /* End the virtual table scan */







>
>
>
>
>







859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
    if( sqlite3IsToplevel(pParse) ){
      pParse->isMultiWrite = 0;
    }
  }else{
    /* Create a record from the argument register contents and insert it into
    ** the ephemeral table. */
    sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
#ifdef SQLITE_DEBUG
    /* Signal an assert() within OP_MakeRecord that it is allowed to
    ** accept no-change records with serial_type 10 */
    sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
#endif
    sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
  }


  if( bOnePass==0 ){
    /* End the virtual table scan */
Changes to src/util.c.
323
324
325
326
327
328
329




















330
331
332
333
334
335
336
337
338

339
340
341
342
343
344
345
/*
** Compute 10 to the E-th power.  Examples:  E==1 results in 10.
** E==2 results in 100.  E==50 results in 1.0e50.
**
** This routine only works for values of E between 1 and 341.
*/
static LONGDOUBLE_TYPE sqlite3Pow10(int E){




















  LONGDOUBLE_TYPE x = 10.0;
  LONGDOUBLE_TYPE r = 1.0;
  while(1){
    if( E & 1 ) r *= x;
    E >>= 1;
    if( E==0 ) break;
    x *= x;
  }
  return r; 

}

/*
** The string z[] is an text representation of a real number.
** Convert this string to a double and write it into *pResult.
**
** The string z[] is length bytes in length (bytes, not characters) and







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









>







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
/*
** Compute 10 to the E-th power.  Examples:  E==1 results in 10.
** E==2 results in 100.  E==50 results in 1.0e50.
**
** This routine only works for values of E between 1 and 341.
*/
static LONGDOUBLE_TYPE sqlite3Pow10(int E){
#if defined(_MSC_VER)
  static const LONGDOUBLE_TYPE x[] = {
    1.0e+001,
    1.0e+002,
    1.0e+004,
    1.0e+008,
    1.0e+016,
    1.0e+032,
    1.0e+064,
    1.0e+128,
    1.0e+256
  };
  LONGDOUBLE_TYPE r = 1.0;
  int i;
  assert( E>=0 && E<=307 );
  for(i=0; E!=0; i++, E >>=1){
    if( E & 1 ) r *= x[i];
  }
  return r;
#else
  LONGDOUBLE_TYPE x = 10.0;
  LONGDOUBLE_TYPE r = 1.0;
  while(1){
    if( E & 1 ) r *= x;
    E >>= 1;
    if( E==0 ) break;
    x *= x;
  }
  return r; 
#endif
}

/*
** The string z[] is an text representation of a real number.
** Convert this string to a double and write it into *pResult.
**
** The string z[] is length bytes in length (bytes, not characters) and
Changes to src/vdbe.c.
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
/*
** Print the value of a register for tracing purposes:
*/
static void memTracePrint(Mem *p){
  if( p->flags & MEM_Undefined ){
    printf(" undefined");
  }else if( p->flags & MEM_Null ){
    printf(" NULL");
  }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
    printf(" si:%lld", p->u.i);
  }else if( p->flags & MEM_Int ){
    printf(" i:%lld", p->u.i);
#ifndef SQLITE_OMIT_FLOATING_POINT
  }else if( p->flags & MEM_Real ){
    printf(" r:%g", p->u.r);







|







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
/*
** Print the value of a register for tracing purposes:
*/
static void memTracePrint(Mem *p){
  if( p->flags & MEM_Undefined ){
    printf(" undefined");
  }else if( p->flags & MEM_Null ){
    printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL");
  }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
    printf(" si:%lld", p->u.i);
  }else if( p->flags & MEM_Int ){
    printf(" i:%lld", p->u.i);
#ifndef SQLITE_OMIT_FLOATING_POINT
  }else if( p->flags & MEM_Real ){
    printf(" r:%g", p->u.r);
2788
2789
2790
2791
2792
2793
2794
2795
2796









2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807

2808
2809
2810
2811
2812
2813
2814

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  pRec = pLast;
  do{
    assert( memIsValid(pRec) );
    pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format, &len);
    if( pRec->flags & MEM_Zero ){









      if( nData ){
        if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
      }else{
        nZero += pRec->u.nZero;
        len -= pRec->u.nZero;
      }
    }
    nData += len;
    testcase( serial_type==127 );
    testcase( serial_type==128 );
    nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);

    if( pRec==pData0 ) break;
    pRec--;
  }while(1);

  /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
  ** which determines the total number of bytes in the header. The varint
  ** value is the size of the header in bytes including the size varint







|

>
>
>
>
>
>
>
>
>
|










>







2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  pRec = pLast;
  do{
    assert( memIsValid(pRec) );
    serial_type = sqlite3VdbeSerialType(pRec, file_format, &len);
    if( pRec->flags & MEM_Zero ){
      if( serial_type==0 ){
        /* Values with MEM_Null and MEM_Zero are created by xColumn virtual
        ** table methods that never invoke sqlite3_result_xxxxx() while
        ** computing an unchanging column value in an UPDATE statement.
        ** Give such values a special internal-use-only serial-type of 10
        ** so that they can be passed through to xUpdate and have
        ** a true sqlite3_value_nochange(). */
        assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
        serial_type = 10;
      }else if( nData ){
        if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
      }else{
        nZero += pRec->u.nZero;
        len -= pRec->u.nZero;
      }
    }
    nData += len;
    testcase( serial_type==127 );
    testcase( serial_type==128 );
    nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
    pRec->uTemp = serial_type;
    if( pRec==pData0 ) break;
    pRec--;
  }while(1);

  /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
  ** which determines the total number of bytes in the header. The varint
  ** value is the size of the header in bytes including the size varint
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
case OP_InsertInt: {
  Mem *pData;       /* MEM cell holding data for the record to be inserted */
  Mem *pKey;        /* MEM cell holding key  for the record */
  VdbeCursor *pC;   /* Cursor to table into which insert is written */
  int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
  const char *zDb;  /* database name - used by the update hook */
  Table *pTab;      /* Table structure - used by update and pre-update hooks */
  int op;           /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
  BtreePayload x;   /* Payload to be inserted */

  op = 0;
  pData = &aMem[pOp->p2];
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( memIsValid(pData) );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );
  assert( pC->uc.pCursor!=0 );







<


<







4421
4422
4423
4424
4425
4426
4427

4428
4429

4430
4431
4432
4433
4434
4435
4436
case OP_InsertInt: {
  Mem *pData;       /* MEM cell holding data for the record to be inserted */
  Mem *pKey;        /* MEM cell holding key  for the record */
  VdbeCursor *pC;   /* Cursor to table into which insert is written */
  int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
  const char *zDb;  /* database name - used by the update hook */
  Table *pTab;      /* Table structure - used by update and pre-update hooks */

  BtreePayload x;   /* Payload to be inserted */


  pData = &aMem[pOp->p2];
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( memIsValid(pData) );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->eCurType==CURTYPE_BTREE );
  assert( pC->uc.pCursor!=0 );
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456

4457
4458
4459
4460
4461





4462
4463
4464
4465
4466
4467
4468
  }

  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    assert( pC->iDb>=0 );
    zDb = db->aDb[pC->iDb].zDbSName;
    pTab = pOp->p4.pTab;
    assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
    op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
  }else{
    pTab = 0; /* Not needed.  Silence a compiler warning. */
    zDb = 0;  /* Not needed.  Silence a compiler warning. */
  }

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  /* Invoke the pre-update hook, if any */

  if( db->xPreUpdateCallback 
   && pOp->p4type==P4_TABLE
   && !(pOp->p5 & OPFLAG_ISUPDATE)
  ){
    sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2);





  }
  if( pOp->p5 & OPFLAG_ISNOOP ) break;
#endif

  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
  assert( pData->flags & (MEM_Blob|MEM_Str) );







<

|





>
|
<
<
<
|
>
>
>
>
>







4450
4451
4452
4453
4454
4455
4456

4457
4458
4459
4460
4461
4462
4463
4464
4465



4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
  }

  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    assert( pC->iDb>=0 );
    zDb = db->aDb[pC->iDb].zDbSName;
    pTab = pOp->p4.pTab;
    assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );

  }else{
    pTab = 0;
    zDb = 0;  /* Not needed.  Silence a compiler warning. */
  }

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  /* Invoke the pre-update hook, if any */
  if( pTab ){
    if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){



      sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey,pOp->p2);
    }
    if( db->xUpdateCallback==0 || pTab->aCol==0 ){
      /* Prevent post-update hook from running in cases when it should not */
      pTab = 0;
    }
  }
  if( pOp->p5 & OPFLAG_ISNOOP ) break;
#endif

  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
  assert( pData->flags & (MEM_Blob|MEM_Str) );
4479
4480
4481
4482
4483
4484
4485

4486

4487


4488
4489
4490
4491
4492
4493
4494
      (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
  );
  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc ) goto abort_due_to_error;

  if( db->xUpdateCallback && op ){

    db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey);


  }
  break;
}

/* Opcode: Delete P1 P2 P3 P4 P5
**
** Delete the record at which the P1 cursor is currently pointing.







>
|
>
|
>
>







4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
      (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
  );
  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc ) goto abort_due_to_error;
  if( pTab ){
    assert( db->xUpdateCallback!=0 );
    assert( pTab->aCol!=0 );
    db->xUpdateCallback(db->pUpdateArg,
           (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT,
           zDb, pTab->zName, x.nKey);
  }
  break;
}

/* Opcode: Delete P1 P2 P3 P4 P5
**
** Delete the record at which the P1 cursor is currently pointing.
6186
6187
6188
6189
6190
6191
6192
6193

6194
6195


6196
6197
6198


6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
  sqlite3_context *pCtx;

  assert( pOp->p4type==P4_FUNCDEF );
  n = pOp->p5;
  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
  pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));

  if( pCtx==0 ) goto no_mem;
  pCtx->pMem = 0;


  pCtx->pFunc = pOp->p4.pFunc;
  pCtx->iOp = (int)(pOp - aOp);
  pCtx->pVdbe = p;


  pCtx->argc = n;
  pOp->p4type = P4_FUNCCTX;
  pOp->p4.pCtx = pCtx;
  pOp->opcode = OP_AggStep;
  /* Fall through into OP_AggStep */
}
case OP_AggStep: {
  int i;
  sqlite3_context *pCtx;
  Mem *pMem;
  Mem t;

  assert( pOp->p4type==P4_FUNCCTX );
  pCtx = pOp->p4.pCtx;
  pMem = &aMem[pOp->p3];

  /* If this function is inside of a trigger, the register array in aMem[]
  ** might change from one evaluation to the next.  The next block of code







|
>


>
>



>
>










<







6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227

6228
6229
6230
6231
6232
6233
6234
  sqlite3_context *pCtx;

  assert( pOp->p4type==P4_FUNCDEF );
  n = pOp->p5;
  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
  pCtx = sqlite3DbMallocRawNN(db, n*sizeof(sqlite3_value*) +
               (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(sqlite3_value*)));
  if( pCtx==0 ) goto no_mem;
  pCtx->pMem = 0;
  pCtx->pOut = (Mem*)&(pCtx->argv[n]);
  sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null);
  pCtx->pFunc = pOp->p4.pFunc;
  pCtx->iOp = (int)(pOp - aOp);
  pCtx->pVdbe = p;
  pCtx->skipFlag = 0;
  pCtx->isError = 0;
  pCtx->argc = n;
  pOp->p4type = P4_FUNCCTX;
  pOp->p4.pCtx = pCtx;
  pOp->opcode = OP_AggStep;
  /* Fall through into OP_AggStep */
}
case OP_AggStep: {
  int i;
  sqlite3_context *pCtx;
  Mem *pMem;


  assert( pOp->p4type==P4_FUNCCTX );
  pCtx = pOp->p4.pCtx;
  pMem = &aMem[pOp->p3];

  /* If this function is inside of a trigger, the register array in aMem[]
  ** might change from one evaluation to the next.  The next block of code
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250

6251







6252
6253
6254
6255
6256
6257
6258
  for(i=0; i<pCtx->argc; i++){
    assert( memIsValid(pCtx->argv[i]) );
    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
  }
#endif

  pMem->n++;
  sqlite3VdbeMemInit(&t, db, MEM_Null);
  pCtx->pOut = &t;
  pCtx->fErrorOrAux = 0;
  pCtx->skipFlag = 0;
  (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
  if( pCtx->fErrorOrAux ){
    if( pCtx->isError ){
      sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
      rc = pCtx->isError;
    }
    sqlite3VdbeMemRelease(&t);
    if( rc ) goto abort_due_to_error;
  }else{
    assert( t.flags==MEM_Null );
  }
  if( pCtx->skipFlag ){
    assert( pOp[-1].opcode==OP_CollSeq );
    i = pOp[-1].p1;
    if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1);

  }







  break;
}

/* Opcode: AggFinal P1 P2 * P4 *
** Synopsis: accum=r[P1] N=P2
**
** Execute the finalizer function for an aggregate.  P1 is







<
|
|
|

|
|
|


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







6243
6244
6245
6246
6247
6248
6249

6250
6251
6252
6253
6254
6255
6256
6257
6258





6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
  for(i=0; i<pCtx->argc; i++){
    assert( memIsValid(pCtx->argv[i]) );
    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
  }
#endif

  pMem->n++;

  assert( pCtx->pOut->flags==MEM_Null );
  assert( pCtx->isError==0 );
  assert( pCtx->skipFlag==0 );
  (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
  if( pCtx->isError ){
    if( pCtx->isError>0 ){
      sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
      rc = pCtx->isError;
    }





    if( pCtx->skipFlag ){
      assert( pOp[-1].opcode==OP_CollSeq );
      i = pOp[-1].p1;
      if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1);
      pCtx->skipFlag = 0;
    }
    sqlite3VdbeMemRelease(pCtx->pOut);
    pCtx->pOut->flags = MEM_Null;
    pCtx->isError = 0;
    if( rc ) goto abort_due_to_error;
  }
  assert( pCtx->pOut->flags==MEM_Null );
  assert( pCtx->skipFlag==0 );
  break;
}

/* Opcode: AggFinal P1 P2 * P4 *
** Synopsis: accum=r[P1] N=P2
**
** Execute the finalizer function for an aggregate.  P1 is
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701






6702
6703
6704
6705
6706
6707
6708
  VdbeBranchTaken(res!=0,2);
  if( res ) goto jump_to_p2;
  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VColumn P1 P2 P3 * *
** Synopsis: r[P3]=vcolumn(P2)
**
** Store the value of the P2-th column of
** the row of the virtual-table that the 
** P1 cursor is pointing to into register P3.






*/
case OP_VColumn: {
  sqlite3_vtab *pVtab;
  const sqlite3_module *pModule;
  Mem *pDest;
  sqlite3_context sContext;








|


|
|
|
>
>
>
>
>
>







6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
  VdbeBranchTaken(res!=0,2);
  if( res ) goto jump_to_p2;
  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VColumn P1 P2 P3 * P5
** Synopsis: r[P3]=vcolumn(P2)
**
** Store in register P3 the value of the P2-th column of
** the current row of the virtual-table of cursor P1.
**
** If the VColumn opcode is being used to fetch the value of
** an unchanging column during an UPDATE operation, then the P5
** value is 1.  Otherwise, P5 is 0.  The P5 value is returned
** by sqlite3_vtab_nochange() routine can can be used
** by virtual table implementations to return special "no-change"
** marks which can be more efficient, depending on the virtual table.
*/
case OP_VColumn: {
  sqlite3_vtab *pVtab;
  const sqlite3_module *pModule;
  Mem *pDest;
  sqlite3_context sContext;

6716
6717
6718
6719
6720
6721
6722





6723

6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
    break;
  }
  pVtab = pCur->uc.pVCur->pVtab;
  pModule = pVtab->pModule;
  assert( pModule->xColumn );
  memset(&sContext, 0, sizeof(sContext));
  sContext.pOut = pDest;





  MemSetTypeFlag(pDest, MEM_Null);

  rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
  sqlite3VtabImportErrmsg(p, pVtab);
  if( sContext.isError ){
    rc = sContext.isError;
  }
  sqlite3VdbeChangeEncoding(pDest, encoding);
  REGISTER_TRACE(pOp->p3, pDest);
  UPDATE_MAX_BLOBSIZE(pDest);

  if( sqlite3VdbeMemTooBig(pDest) ){







>
>
>
>
>
|
>


|







6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
    break;
  }
  pVtab = pCur->uc.pVCur->pVtab;
  pModule = pVtab->pModule;
  assert( pModule->xColumn );
  memset(&sContext, 0, sizeof(sContext));
  sContext.pOut = pDest;
  if( pOp->p5 ){
    sqlite3VdbeMemSetNull(pDest);
    pDest->flags = MEM_Null|MEM_Zero;
    pDest->u.nZero = 0;
  }else{
    MemSetTypeFlag(pDest, MEM_Null);
  }
  rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
  sqlite3VtabImportErrmsg(p, pVtab);
  if( sContext.isError>0 ){
    rc = sContext.isError;
  }
  sqlite3VdbeChangeEncoding(pDest, encoding);
  REGISTER_TRACE(pOp->p3, pDest);
  UPDATE_MAX_BLOBSIZE(pDest);

  if( sqlite3VdbeMemTooBig(pDest) ){
6984
6985
6986
6987
6988
6989
6990

6991
6992
6993
6994
6995
6996
6997
  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
  pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
  if( pCtx==0 ) goto no_mem;
  pCtx->pOut = 0;
  pCtx->pFunc = pOp->p4.pFunc;
  pCtx->iOp = (int)(pOp - aOp);
  pCtx->pVdbe = p;

  pCtx->argc = n;
  pOp->p4type = P4_FUNCCTX;
  pOp->p4.pCtx = pCtx;
  assert( OP_PureFunc == OP_PureFunc0+2 );
  assert( OP_Function == OP_Function0+2 );
  pOp->opcode += 2;
  /* Fall through into OP_Function */







>







7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
  pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
  if( pCtx==0 ) goto no_mem;
  pCtx->pOut = 0;
  pCtx->pFunc = pOp->p4.pFunc;
  pCtx->iOp = (int)(pOp - aOp);
  pCtx->pVdbe = p;
  pCtx->isError = 0;
  pCtx->argc = n;
  pOp->p4type = P4_FUNCCTX;
  pOp->p4.pCtx = pCtx;
  assert( OP_PureFunc == OP_PureFunc0+2 );
  assert( OP_Function == OP_Function0+2 );
  pOp->opcode += 2;
  /* Fall through into OP_Function */
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034

7035
7036
7037
7038
7039
7040
7041
#ifdef SQLITE_DEBUG
  for(i=0; i<pCtx->argc; i++){
    assert( memIsValid(pCtx->argv[i]) );
    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
  }
#endif
  MemSetTypeFlag(pOut, MEM_Null);
  pCtx->fErrorOrAux = 0;
  (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */

  /* If the function returned an error, throw an exception */
  if( pCtx->fErrorOrAux ){
    if( pCtx->isError ){
      sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut));
      rc = pCtx->isError;
    }
    sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);

    if( rc ) goto abort_due_to_error;
  }

  /* Copy the result of the function into register P3 */
  if( pOut->flags & (MEM_Str|MEM_Blob) ){
    sqlite3VdbeChangeEncoding(pOut, encoding);
    if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;







|



|
|




>







7051
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
#ifdef SQLITE_DEBUG
  for(i=0; i<pCtx->argc; i++){
    assert( memIsValid(pCtx->argv[i]) );
    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
  }
#endif
  MemSetTypeFlag(pOut, MEM_Null);
  assert( pCtx->isError==0 );
  (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */

  /* If the function returned an error, throw an exception */
  if( pCtx->isError ){
    if( pCtx->isError>0 ){
      sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut));
      rc = pCtx->isError;
    }
    sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
    pCtx->isError = 0;
    if( rc ) goto abort_due_to_error;
  }

  /* Copy the result of the function into register P3 */
  if( pOut->flags & (MEM_Str|MEM_Blob) ){
    sqlite3VdbeChangeEncoding(pOut, encoding);
    if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
7069
7070
7071
7072
7073
7074
7075


7076
7077
7078
7079
7080
7081
7082
7083
7084
** first time they are evaluated for this run.
**
** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
** error is encountered.
*/
case OP_Trace:
case OP_Init: {          /* jump */


  char *zTrace;
  int i;

  /* If the P4 argument is not NULL, then it must be an SQL comment string.
  ** The "--" string is broken up to prevent false-positives with srcck1.c.
  **
  ** This assert() provides evidence for:
  ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that
  ** would have been returned by the legacy sqlite3_trace() interface by







>
>

|







7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
** first time they are evaluated for this run.
**
** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
** error is encountered.
*/
case OP_Trace:
case OP_Init: {          /* jump */
  int i;
#ifndef SQLITE_OMIT_TRACE
  char *zTrace;
#endif

  /* If the P4 argument is not NULL, then it must be an SQL comment string.
  ** The "--" string is broken up to prevent false-positives with srcck1.c.
  **
  ** This assert() provides evidence for:
  ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that
  ** would have been returned by the legacy sqlite3_trace() interface by
Changes to src/vdbe.h.
123
124
125
126
127
128
129

130
131
132
133
134
135
136
#define P4_EXPR       (-10) /* P4 is a pointer to an Expr tree */
#define P4_MEM        (-11) /* P4 is a pointer to a Mem*    structure */
#define P4_VTAB       (-12) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_REAL       (-13) /* P4 is a 64-bit floating point value */
#define P4_INT64      (-14) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY   (-15) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX    (-16) /* P4 is a pointer to an sqlite3_context object */


/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
#define P5_ConstraintUnique  2
#define P5_ConstraintCheck   3
#define P5_ConstraintFK      4








>







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#define P4_EXPR       (-10) /* P4 is a pointer to an Expr tree */
#define P4_MEM        (-11) /* P4 is a pointer to a Mem*    structure */
#define P4_VTAB       (-12) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_REAL       (-13) /* P4 is a 64-bit floating point value */
#define P4_INT64      (-14) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY   (-15) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX    (-16) /* P4 is a pointer to an sqlite3_context object */
#define P4_DYNBLOB    (-17) /* Pointer to memory from sqliteMalloc() */

/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
#define P5_ConstraintUnique  2
#define P5_ConstraintCheck   3
#define P5_ConstraintFK      4

Changes to src/vdbeInt.h.
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
  Mem *pOut;              /* The return value is stored here */
  FuncDef *pFunc;         /* Pointer to function information */
  Mem *pMem;              /* Memory cell used to store aggregate context */
  Vdbe *pVdbe;            /* The VM that owns this context */
  int iOp;                /* Instruction number of OP_Function */
  int isError;            /* Error code returned by the function. */
  u8 skipFlag;            /* Skip accumulator loading if true */
  u8 fErrorOrAux;         /* isError!=0 or pVdbe->pAuxData modified */
  u8 argc;                /* Number of arguments */
  sqlite3_value *argv[1]; /* Argument set */
};

/* A bitfield type for use inside of structures.  Always follow with :N where
** N is the number of bits.
*/







<







313
314
315
316
317
318
319

320
321
322
323
324
325
326
  Mem *pOut;              /* The return value is stored here */
  FuncDef *pFunc;         /* Pointer to function information */
  Mem *pMem;              /* Memory cell used to store aggregate context */
  Vdbe *pVdbe;            /* The VM that owns this context */
  int iOp;                /* Instruction number of OP_Function */
  int isError;            /* Error code returned by the function. */
  u8 skipFlag;            /* Skip accumulator loading if true */

  u8 argc;                /* Number of arguments */
  sqlite3_value *argv[1]; /* Argument set */
};

/* A bitfield type for use inside of structures.  Always follow with :N where
** N is the number of bits.
*/
Changes to src/vdbeapi.c.
263
264
265
266
267
268
269





270
271
272
273
274
275
276
     SQLITE_INTEGER,  /* 0x1c */
     SQLITE_NULL,     /* 0x1d */
     SQLITE_INTEGER,  /* 0x1e */
     SQLITE_NULL,     /* 0x1f */
  };
  return aType[pVal->flags&MEM_AffMask];
}






/* Make a copy of an sqlite3_value object
*/
sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
  sqlite3_value *pNew;
  if( pOrig==0 ) return 0;
  pNew = sqlite3_malloc( sizeof(*pNew) );







>
>
>
>
>







263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
     SQLITE_INTEGER,  /* 0x1c */
     SQLITE_NULL,     /* 0x1d */
     SQLITE_INTEGER,  /* 0x1e */
     SQLITE_NULL,     /* 0x1f */
  };
  return aType[pVal->flags&MEM_AffMask];
}

/* Return true if a parameter to xUpdate represents an unchanged column */
int sqlite3_value_nochange(sqlite3_value *pVal){
  return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero);
}

/* Make a copy of an sqlite3_value object
*/
sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
  sqlite3_value *pNew;
  if( pOrig==0 ) return 0;
  pNew = sqlite3_malloc( sizeof(*pNew) );
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  pCtx->isError = SQLITE_ERROR;
  pCtx->fErrorOrAux = 1;
  sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  pCtx->isError = SQLITE_ERROR;
  pCtx->fErrorOrAux = 1;
  sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}







<






<







368
369
370
371
372
373
374

375
376
377
378
379
380

381
382
383
384
385
386
387
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  pCtx->isError = SQLITE_ERROR;

  sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  pCtx->isError = SQLITE_ERROR;

  sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
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
  if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
    return SQLITE_TOOBIG;
  }
  sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
  return SQLITE_OK;
}
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
  pCtx->isError = errCode;
  pCtx->fErrorOrAux = 1;
#ifdef SQLITE_DEBUG
  if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
#endif
  if( pCtx->pOut->flags & MEM_Null ){
    sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, 
                         SQLITE_UTF8, SQLITE_STATIC);
  }
}

/* Force an SQLITE_TOOBIG error. */
void sqlite3_result_error_toobig(sqlite3_context *pCtx){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  pCtx->isError = SQLITE_TOOBIG;
  pCtx->fErrorOrAux = 1;
  sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, 
                       SQLITE_UTF8, SQLITE_STATIC);
}

/* An SQLITE_NOMEM error. */
void sqlite3_result_error_nomem(sqlite3_context *pCtx){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetNull(pCtx->pOut);
  pCtx->isError = SQLITE_NOMEM_BKPT;
  pCtx->fErrorOrAux = 1;
  sqlite3OomFault(pCtx->pOut->db);
}

/*
** This function is called after a transaction has been committed. It 
** invokes callbacks registered with sqlite3_wal_hook() as required.
*/







|
<













<









<







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
  if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
    return SQLITE_TOOBIG;
  }
  sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
  return SQLITE_OK;
}
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
  pCtx->isError = errCode ? errCode : -1;

#ifdef SQLITE_DEBUG
  if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
#endif
  if( pCtx->pOut->flags & MEM_Null ){
    sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, 
                         SQLITE_UTF8, SQLITE_STATIC);
  }
}

/* Force an SQLITE_TOOBIG error. */
void sqlite3_result_error_toobig(sqlite3_context *pCtx){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  pCtx->isError = SQLITE_TOOBIG;

  sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, 
                       SQLITE_UTF8, SQLITE_STATIC);
}

/* An SQLITE_NOMEM error. */
void sqlite3_result_error_nomem(sqlite3_context *pCtx){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetNull(pCtx->pOut);
  pCtx->isError = SQLITE_NOMEM_BKPT;

  sqlite3OomFault(pCtx->pOut->db);
}

/*
** This function is called after a transaction has been committed. It 
** invokes callbacks registered with sqlite3_wal_hook() as required.
*/
740
741
742
743
744
745
746



















747
748
749
750
751
752
753
** sqlite3_create_function16() routines that originally registered the
** application defined function.
*/
sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
  assert( p && p->pOut );
  return p->pOut->db;
}




















/*
** Return the current time for a statement.  If the current time
** is requested more than once within the same run of a single prepared
** statement, the exact same time is returned for each invocation regardless
** of the amount of time that elapses between invocations.  In other words,
** the time returned is always the time of the first call.







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







740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
** sqlite3_create_function16() routines that originally registered the
** application defined function.
*/
sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
  assert( p && p->pOut );
  return p->pOut->db;
}

/*
** If this routine is invoked from within an xColumn method of a virtual
** table, then it returns true if and only if the the call is during an
** UPDATE operation and the value of the column will not be modified
** by the UPDATE.
**
** If this routine is called from any context other than within the
** xColumn method of a virtual table, then the return value is meaningless
** and arbitrary.
**
** Virtual table implements might use this routine to optimize their
** performance by substituting a NULL result, or some other light-weight
** value, as a signal to the xUpdate routine that the column is unchanged.
*/
int sqlite3_vtab_nochange(sqlite3_context *p){
  assert( p );
  return sqlite3_value_nochange(p->pOut);
}

/*
** Return the current time for a statement.  If the current time
** is requested more than once within the same run of a single prepared
** statement, the exact same time is returned for each invocation regardless
** of the amount of time that elapses between invocations.  In other words,
** the time returned is always the time of the first call.
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
  if( pAuxData==0 ){
    pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
    if( !pAuxData ) goto failed;
    pAuxData->iAuxOp = pCtx->iOp;
    pAuxData->iAuxArg = iArg;
    pAuxData->pNextAux = pVdbe->pAuxData;
    pVdbe->pAuxData = pAuxData;
    if( pCtx->fErrorOrAux==0 ){
      pCtx->isError = 0;
      pCtx->fErrorOrAux = 1;
    }
  }else if( pAuxData->xDeleteAux ){
    pAuxData->xDeleteAux(pAuxData->pAux);
  }

  pAuxData->pAux = pAux;
  pAuxData->xDeleteAux = xDelete;
  return;







<
|
<
<







908
909
910
911
912
913
914

915


916
917
918
919
920
921
922
  if( pAuxData==0 ){
    pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
    if( !pAuxData ) goto failed;
    pAuxData->iAuxOp = pCtx->iOp;
    pAuxData->iAuxArg = iArg;
    pAuxData->pNextAux = pVdbe->pAuxData;
    pVdbe->pAuxData = pAuxData;

    if( pCtx->isError==0 ) pCtx->isError = -1;


  }else if( pAuxData->xDeleteAux ){
    pAuxData->xDeleteAux(pAuxData->pAux);
  }

  pAuxData->pAux = pAux;
  pAuxData->xDeleteAux = xDelete;
  return;
Changes to src/vdbeaux.c.
862
863
864
865
866
867
868

869
870
871
872
873
874
875
    case P4_FUNCCTX: {
      freeP4FuncCtx(db, (sqlite3_context*)p4);
      break;
    }
    case P4_REAL:
    case P4_INT64:
    case P4_DYNAMIC:

    case P4_INTARRAY: {
      sqlite3DbFree(db, p4);
      break;
    }
    case P4_KEYINFO: {
      if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
      break;







>







862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
    case P4_FUNCCTX: {
      freeP4FuncCtx(db, (sqlite3_context*)p4);
      break;
    }
    case P4_REAL:
    case P4_INT64:
    case P4_DYNAMIC:
    case P4_DYNBLOB:
    case P4_INTARRAY: {
      sqlite3DbFree(db, p4);
      break;
    }
    case P4_KEYINFO: {
      if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
      break;
1403
1404
1405
1406
1407
1408
1409

1410
1411
1412
1413
1414
1415
1416
      sqlite3StrAccumAppend(&x, "]", 1);
      break;
    }
    case P4_SUBPROGRAM: {
      sqlite3XPrintf(&x, "program");
      break;
    }

    case P4_ADVANCE: {
      zTemp[0] = 0;
      break;
    }
    case P4_TABLE: {
      sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName);
      break;







>







1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
      sqlite3StrAccumAppend(&x, "]", 1);
      break;
    }
    case P4_SUBPROGRAM: {
      sqlite3XPrintf(&x, "program");
      break;
    }
    case P4_DYNBLOB:
    case P4_ADVANCE: {
      zTemp[0] = 0;
      break;
    }
    case P4_TABLE: {
      sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName);
      break;
3448
3449
3450
3451
3452
3453
3454
3455






3456
3457
3458
3459
3460
3461
3462
}
u32 sqlite3VdbeSerialGet(
  const unsigned char *buf,     /* Buffer to deserialize from */
  u32 serial_type,              /* Serial type to deserialize */
  Mem *pMem                     /* Memory cell to write value into */
){
  switch( serial_type ){
    case 10:   /* Reserved for future use */






    case 11:   /* Reserved for future use */
    case 0: {  /* Null */
      /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
      pMem->flags = MEM_Null;
      break;
    }
    case 1: {







|
>
>
>
>
>
>







3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
}
u32 sqlite3VdbeSerialGet(
  const unsigned char *buf,     /* Buffer to deserialize from */
  u32 serial_type,              /* Serial type to deserialize */
  Mem *pMem                     /* Memory cell to write value into */
){
  switch( serial_type ){
    case 10: { /* Internal use only: NULL with virtual table
               ** UPDATE no-change flag set */
      pMem->flags = MEM_Null|MEM_Zero;
      pMem->n = 0;
      pMem->u.nZero = 0;
      break;
    }
    case 11:   /* Reserved for future use */
    case 0: {  /* Null */
      /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
      pMem->flags = MEM_Null;
      break;
    }
    case 1: {
Changes to src/vdbemem.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

  /* Cannot be both MEM_Int and MEM_Real at the same time */
  assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );

  if( p->flags & MEM_Null ){
    /* Cannot be both MEM_Null and some other type */
    assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
                         |MEM_RowSet|MEM_Frame|MEM_Agg|MEM_Zero))==0 );

    /* If MEM_Null is set, then either the value is a pure NULL (the usual
    ** case) or it is a pointer set using sqlite3_bind_pointer() or
    ** sqlite3_result_pointer().  If a pointer, then MEM_Term must also be
    ** set.
    */
    if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

  /* Cannot be both MEM_Int and MEM_Real at the same time */
  assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );

  if( p->flags & MEM_Null ){
    /* Cannot be both MEM_Null and some other type */
    assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
                         |MEM_RowSet|MEM_Frame|MEM_Agg))==0 );

    /* If MEM_Null is set, then either the value is a pure NULL (the usual
    ** case) or it is a pointer set using sqlite3_bind_pointer() or
    ** sqlite3_result_pointer().  If a pointer, then MEM_Term must also be
    ** set.
    */
    if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){
577
578
579
580
581
582
583












584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  pMem->u.r = sqlite3VdbeRealValue(pMem);
  MemSetTypeFlag(pMem, MEM_Real);
  return SQLITE_OK;
}













/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
int sqlite3VdbeMemNumerify(Mem *pMem){
  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
    int rc;
    assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
    if( rc==0 ){
      MemSetTypeFlag(pMem, MEM_Int);
    }else{
      i64 i = pMem->u.i;
      sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
      if( rc==1 && pMem->u.r==(double)i ){
        pMem->u.i = i;
        MemSetTypeFlag(pMem, MEM_Int);
      }else{
        MemSetTypeFlag(pMem, MEM_Real);
      }
    }
  }







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




















|







577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  pMem->u.r = sqlite3VdbeRealValue(pMem);
  MemSetTypeFlag(pMem, MEM_Real);
  return SQLITE_OK;
}

/* Compare a floating point value to an integer.  Return true if the two
** values are the same within the precision of the floating point value.
**
** For some versions of GCC on 32-bit machines, if you do the more obvious
** comparison of "r1==(double)i" you sometimes get an answer of false even
** though the r1 and (double)i values are bit-for-bit the same.
*/
static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
  double r2 = (double)i;
  return memcmp(&r1, &r2, sizeof(r1))==0;
}

/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
int sqlite3VdbeMemNumerify(Mem *pMem){
  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
    int rc;
    assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
    if( rc==0 ){
      MemSetTypeFlag(pMem, MEM_Int);
    }else{
      i64 i = pMem->u.i;
      sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
      if( rc==1 && sqlite3RealSameAsInt(pMem->u.r, i) ){
        pMem->u.i = i;
        MemSetTypeFlag(pMem, MEM_Int);
      }else{
        MemSetTypeFlag(pMem, MEM_Real);
      }
    }
  }
Changes to src/where.c.
4797
4798
4799
4800
4801
4802
4803
















4804
4805
4806
4807
4808
4809
4810
4811

4812
4813
4814
4815
4816
4817
4818
4819
    }
  }
  WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
  pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;

  /* If the caller is an UPDATE or DELETE statement that is requesting
  ** to use a one-pass algorithm, determine if this is appropriate.
















  */
  assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
  if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
    int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
    int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
    if( bOnerow
     || ((wctrlFlags & WHERE_ONEPASS_MULTIROW)!=0
           && 0==(wsFlags & WHERE_VIRTUALTABLE))

    ){
      pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
      if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
        if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
          bFordelete = OPFLAG_FORDELETE;
        }
        pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
      }







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





|
|
|
>
|







4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
    }
  }
  WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
  pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;

  /* If the caller is an UPDATE or DELETE statement that is requesting
  ** to use a one-pass algorithm, determine if this is appropriate.
  **
  ** A one-pass approach can be used if the caller has requested one
  ** and either (a) the scan visits at most one row or (b) each
  ** of the following are true:
  **
  **   * the caller has indicated that a one-pass approach can be used
  **     with multiple rows (by setting WHERE_ONEPASS_MULTIROW), and
  **   * the table is not a virtual table, and
  **   * either the scan does not use the OR optimization or the caller
  **     is a DELETE operation (WHERE_DUPLICATES_OK is only specified
  **     for DELETE).
  **
  ** The last qualification is because an UPDATE statement uses
  ** WhereInfo.aiCurOnePass[1] to determine whether or not it really can
  ** use a one-pass approach, and this is not set accurately for scans
  ** that use the OR optimization.
  */
  assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
  if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
    int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
    int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
    if( bOnerow || (
        0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
     && 0==(wsFlags & WHERE_VIRTUALTABLE)
     && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
    )){
      pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
      if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
        if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
          bFordelete = OPFLAG_FORDELETE;
        }
        pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
      }
Changes to src/wherecode.c.
2166
2167
2168
2169
2170
2171
2172






2173
2174
2175
2176
2177
2178
2179
    pE = pTerm->pExpr;
    assert( !ExprHasProperty(pE, EP_FromJoin) );
    assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
    pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
                    WO_EQ|WO_IN|WO_IS, 0);
    if( pAlt==0 ) continue;
    if( pAlt->wtFlags & (TERM_CODED) ) continue;






    testcase( pAlt->eOperator & WO_EQ );
    testcase( pAlt->eOperator & WO_IS );
    testcase( pAlt->eOperator & WO_IN );
    VdbeModuleComment((v, "begin transitive constraint"));
    sEAlt = *pAlt->pExpr;
    sEAlt.pLeft = pE->pLeft;
    sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL);







>
>
>
>
>
>







2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
    pE = pTerm->pExpr;
    assert( !ExprHasProperty(pE, EP_FromJoin) );
    assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
    pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
                    WO_EQ|WO_IN|WO_IS, 0);
    if( pAlt==0 ) continue;
    if( pAlt->wtFlags & (TERM_CODED) ) continue;
    if( (pAlt->eOperator & WO_IN) 
     && (pAlt->pExpr->flags & EP_xIsSelect)
     && (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
    ){
      continue;
    }
    testcase( pAlt->eOperator & WO_EQ );
    testcase( pAlt->eOperator & WO_IS );
    testcase( pAlt->eOperator & WO_IN );
    VdbeModuleComment((v, "begin transitive constraint"));
    sEAlt = *pAlt->pExpr;
    sEAlt.pLeft = pE->pLeft;
    sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL);
Changes to test/capi2.test.
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {}}
do_test capi2-3.2 {
  set rc [catch {
      sqlite3_prepare $DB {select bogus from } -1 TAIL
  } msg]
  lappend rc $msg $TAIL
} {1 {(1) near " ": syntax error} {}}
do_test capi2-3.3 {
  set rc [catch {
      sqlite3_prepare $DB {;;;;select bogus from sqlite_master} -1 TAIL
  } msg]
  lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {}}
do_test capi2-3.4 {







|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {}}
do_test capi2-3.2 {
  set rc [catch {
      sqlite3_prepare $DB {select bogus from } -1 TAIL
  } msg]
  lappend rc $msg $TAIL
} {1 {(1) incomplete input} {}}
do_test capi2-3.3 {
  set rc [catch {
      sqlite3_prepare $DB {;;;;select bogus from sqlite_master} -1 TAIL
  } msg]
  lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {}}
do_test capi2-3.4 {
Changes to test/capi3.test.
645
646
647
648
649
650
651












652
653
654
655
656
657
658

check_header $STMT capi3-5.31 {x y z} {VARINT {} {}}
check_origin_header $STMT capi3-5.32 {main {} {}} {t1 {} {}} {a {} {}}
do_test capi3-5.33 {
  sqlite3_finalize $STMT
} SQLITE_OK














set ::ENC [execsql {pragma encoding}]
db close

do_test capi3-6.0 {
  sqlite3 db test.db
  set DB [sqlite3_connection_pointer db]







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







645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670

check_header $STMT capi3-5.31 {x y z} {VARINT {} {}}
check_origin_header $STMT capi3-5.32 {main {} {}} {t1 {} {}} {a {} {}}
do_test capi3-5.33 {
  sqlite3_finalize $STMT
} SQLITE_OK

# 2018-01-09:  If a column is the last token if a string, the column name
# was not being set correctly, due to changes in check-in
# https://sqlite.org/src/info/0fdf97efe5df7455
#
# This problem was detected by the community during beta-testing.
#
do_test capi3-5.34 {
  set STMT [sqlite3_prepare $DB {SELECT :a, :b} -1 TAIL]
  sqlite3_column_count $STMT
} 2
check_header $STMT capi-5.35 {:a :b} {{} {}}
sqlite3_finalize $STMT

set ::ENC [execsql {pragma encoding}]
db close

do_test capi3-6.0 {
  sqlite3 db test.db
  set DB [sqlite3_connection_pointer db]
Changes to test/colname.test.
389
390
391
392
393
394
395

396
397
398
399

400
401
402
403
404
405
406
  DROP TABLE IF EXISTS t2;
  CREATE TABLE t1(aaa INT);
  INSERT INTO t1(aaa) VALUES(123);
}
do_test colname-9.310 {
  execsql2 {SELECT BBb FROM (SELECT aaa AS Bbb FROM t1)}
} {Bbb 123}

do_execsql_test colname-9.320 {
  CREATE TABLE t2 AS SELECT BBb FROM (SELECT aaa AS Bbb FROM t1);
  SELECT name FROM pragma_table_info('t2');
} {Bbb}


# Issue detected by OSSFuzz on 2017-12-24 (Christmas Eve)
# caused by check-in https://sqlite.org/src/info/6b2ff26c25
#
# Prior to being fixed, the following CREATE TABLE was dereferencing
# a NULL pointer and segfaulting.
#







>
|
|
|
|
>







389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  DROP TABLE IF EXISTS t2;
  CREATE TABLE t1(aaa INT);
  INSERT INTO t1(aaa) VALUES(123);
}
do_test colname-9.310 {
  execsql2 {SELECT BBb FROM (SELECT aaa AS Bbb FROM t1)}
} {Bbb 123}
ifcapable vtab {
  do_execsql_test colname-9.320 {
    CREATE TABLE t2 AS SELECT BBb FROM (SELECT aaa AS Bbb FROM t1);
    SELECT name FROM pragma_table_info('t2');
  } {Bbb}
}

# Issue detected by OSSFuzz on 2017-12-24 (Christmas Eve)
# caused by check-in https://sqlite.org/src/info/6b2ff26c25
#
# Prior to being fixed, the following CREATE TABLE was dereferencing
# a NULL pointer and segfaulting.
#
Changes to test/crash8.test.
138
139
140
141
142
143
144

145
146
147
148
149
150
151
# Also test that SQLite will not rollback a hot-journal file with a
# suspect page-size. In this case "suspect" means:
# 
#    a) Not a power of 2, or
#    b) Less than 512, or
#    c) Greater than SQLITE_MAX_PAGE_SIZE
#

do_test crash8-3.1 {
  list [file exists test.db-joural] [file exists test.db]
} {0 1}
do_test crash8-3.2 {
  execsql {
    PRAGMA synchronous = off;
    BEGIN;







>







138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# Also test that SQLite will not rollback a hot-journal file with a
# suspect page-size. In this case "suspect" means:
# 
#    a) Not a power of 2, or
#    b) Less than 512, or
#    c) Greater than SQLITE_MAX_PAGE_SIZE
#
if {[atomic_batch_write test.db]==0} {
do_test crash8-3.1 {
  list [file exists test.db-joural] [file exists test.db]
} {0 1}
do_test crash8-3.2 {
  execsql {
    PRAGMA synchronous = off;
    BEGIN;
224
225
226
227
228
229
230

231
232
233
234
235
236
237
  puts -nonewline $fd $zJournal
  close $fd
  execsql { 
    SELECT count(*) FROM t1;
    PRAGMA integrity_check
  }
} {6 ok}



# If a connection running in persistent-journal mode is part of a 
# multi-file transaction, it must ensure that the master-journal name
# appended to the journal file contents during the commit is located
# at the end of the physical journal file. If there was already a
# large journal file allocated at the start of the transaction, this







>







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  puts -nonewline $fd $zJournal
  close $fd
  execsql { 
    SELECT count(*) FROM t1;
    PRAGMA integrity_check
  }
} {6 ok}
}


# If a connection running in persistent-journal mode is part of a 
# multi-file transaction, it must ensure that the master-journal name
# appended to the journal file contents during the commit is located
# at the end of the physical journal file. If there was already a
# large journal file allocated at the start of the transaction, this
262
263
264
265
266
267
268



269
270

271
272
273
274
275
276
277
      PRAGMA aux.journal_mode = persist;
      CREATE TABLE aux.ab(a, b);
      INSERT INTO aux.ab SELECT * FROM main.ab;

      UPDATE aux.ab SET b = randstr(1000,1000) WHERE a>=1;
      UPDATE ab SET b = randstr(1000,1000) WHERE a>=1;
    }



    list [file exists test.db-journal] [file exists test2.db-journal]
  } {1 1}


  do_test crash8-4.2 {
    execsql {
      BEGIN;
        UPDATE aux.ab SET b = 'def' WHERE a = 0;
        UPDATE main.ab SET b = 'def' WHERE a = 0;
      COMMIT;







>
>
>
|
|
>







264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
      PRAGMA aux.journal_mode = persist;
      CREATE TABLE aux.ab(a, b);
      INSERT INTO aux.ab SELECT * FROM main.ab;

      UPDATE aux.ab SET b = randstr(1000,1000) WHERE a>=1;
      UPDATE ab SET b = randstr(1000,1000) WHERE a>=1;
    }
  } {persist persist}
  if {[atomic_batch_write test.db]==0} {
    do_test crash8.4.1.1 {
      list [file exists test.db-journal] [file exists test2.db-journal]
    } {1 1}
  }

  do_test crash8-4.2 {
    execsql {
      BEGIN;
        UPDATE aux.ab SET b = 'def' WHERE a = 0;
        UPDATE main.ab SET b = 'def' WHERE a = 0;
      COMMIT;
Changes to test/delete_db.test.
12
13
14
15
16
17
18





19
20
21
22
23
24
25
# focus of this file is testing the code in test_delete.c (the
# sqlite3_delete_database() API).
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix delete_db






proc delete_all {} {
  foreach f [glob -nocomplain test2*] { file delete $f }
  foreach f [glob -nocomplain test3*] { file delete $f }
}

proc copydb {} {







>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# focus of this file is testing the code in test_delete.c (the
# sqlite3_delete_database() API).
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix delete_db

if {[atomic_batch_write test.db]} {
  finish_test
  return
}

proc delete_all {} {
  foreach f [glob -nocomplain test2*] { file delete $f }
  foreach f [glob -nocomplain test3*] { file delete $f }
}

proc copydb {} {
Changes to test/exclusive.test.
248
249
250
251
252
253
254
255


256
257
258
259
260
261
262
# truncates instead of deletes the journal file when committing 
# a transaction.
#
# These tests are not run on windows because the windows backend
# opens the journal file for exclusive access, preventing its contents 
# from being inspected externally.
#
if {$tcl_platform(platform) != "windows"} {



  # Return a list of two booleans (either 0 or 1). The first is true
  # if the named file exists. The second is true only if the file
  # exists and the first 28 bytes contain at least one non-zero byte.
  #
  proc filestate {fname} {
    set exists 0







|
>
>







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# truncates instead of deletes the journal file when committing 
# a transaction.
#
# These tests are not run on windows because the windows backend
# opens the journal file for exclusive access, preventing its contents 
# from being inspected externally.
#
if {$tcl_platform(platform) != "windows"
 && [atomic_batch_write test.db]==0
} {

  # Return a list of two booleans (either 0 or 1). The first is true
  # if the named file exists. The second is true only if the file
  # exists and the first 28 bytes contain at least one non-zero byte.
  #
  proc filestate {fname} {
    set exists 0
387
388
389
390
391
392
393

394
395
396
397
398
399
400
  }
} {normal}

#----------------------------------------------------------------------
# Tests exclusive-5.X - test that statement journals are truncated
# instead of deleted when in exclusive access mode.
#


# Close and reopen the database so that the temp database is no
# longer active.
#
db close
sqlite3 db test.db








>







389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  }
} {normal}

#----------------------------------------------------------------------
# Tests exclusive-5.X - test that statement journals are truncated
# instead of deleted when in exclusive access mode.
#
if {[atomic_batch_write test.db]==0} {

# Close and reopen the database so that the temp database is no
# longer active.
#
db close
sqlite3 db test.db

503
504
505
506
507
508
509
510


511
  sqlite3 db test.db
} {}

do_execsql_test exclusive-6.5 {
  PRAGMA locking_mode = EXCLUSIVE;
  SELECT * FROM sqlite_master;
} {exclusive}



finish_test








>
>

506
507
508
509
510
511
512
513
514
515
516
  sqlite3 db test.db
} {}

do_execsql_test exclusive-6.5 {
  PRAGMA locking_mode = EXCLUSIVE;
  SELECT * FROM sqlite_master;
} {exclusive}

} ;# atomic_batch_write==0

finish_test
Changes to test/fallocate.test.
57
58
59
60
61
62
63

64
65
66
67
68
69
70
# causes a database file to grow, the database grows to its previous size
# on disk, not to the minimum size required to hold the database image.
#
do_test fallocate-1.7 {
  execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
  if {[permutation] != "inmemory_journal"
   && [permutation] != "atomic-batch-write"

  } {
    hexio_get_int [hexio_read test.db-journal 16 4]
  } else {
    set {} 1024
  }
} {1024}
do_test fallocate-1.8 { execsql { COMMIT } } {}







>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# causes a database file to grow, the database grows to its previous size
# on disk, not to the minimum size required to hold the database image.
#
do_test fallocate-1.7 {
  execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
  if {[permutation] != "inmemory_journal"
   && [permutation] != "atomic-batch-write"
   && [atomic_batch_write test.db]==0
  } {
    hexio_get_int [hexio_read test.db-journal 16 4]
  } else {
    set {} 1024
  }
} {1024}
do_test fallocate-1.8 { execsql { COMMIT } } {}
Changes to test/fkey1.test.
170
171
172
173
174
175
176

177
178
179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
do_catchsql_test fkey1-5.2 {
  INSERT OR REPLACE INTO t11 VALUES (2, 3);
} {1 {FOREIGN KEY constraint failed}}

# Make sure sqlite3_trace() output works with triggers used to implement
# FK constraints
#

proc sqltrace {txt} {
  global traceoutput
  lappend traceoutput $txt
}
do_test fkey1-5.2.1 {
  unset -nocomplain traceoutput
  db trace sqltrace
  catch {db eval {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
  set traceoutput
} {{INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);}}


# A similar test to the above.
do_execsql_test fkey1-5.3 {
  CREATE TABLE Foo (
    Id INTEGER PRIMARY KEY, 
    ParentId INTEGER REFERENCES Foo(Id) ON DELETE CASCADE, C1
  );







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







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
do_catchsql_test fkey1-5.2 {
  INSERT OR REPLACE INTO t11 VALUES (2, 3);
} {1 {FOREIGN KEY constraint failed}}

# Make sure sqlite3_trace() output works with triggers used to implement
# FK constraints
#
ifcapable trace {
  proc sqltrace {txt} {
    global traceoutput
    lappend traceoutput $txt
  }
  do_test fkey1-5.2.1 {
    unset -nocomplain traceoutput
    db trace sqltrace
    catch {db eval {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
    set traceoutput
  } {{INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
}

# A similar test to the above.
do_execsql_test fkey1-5.3 {
  CREATE TABLE Foo (
    Id INTEGER PRIMARY KEY, 
    ParentId INTEGER REFERENCES Foo(Id) ON DELETE CASCADE, C1
  );
Changes to test/fts3rank.test.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the FTS3 module.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fts3expr5

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
  finish_test
  return
}








|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the FTS3 module.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fts3rank

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
  finish_test
  return
}

52
53
54
55
56
57
58

59
60
61




62
63
64

  SELECT * FROM t1 ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
} {1 {invalid matchinfo blob passed to function rank()}}

do_catchsql_test 1.4 {
  SELECT * FROM t1 ORDER BY rank(x'0000000000000000') DESC, rowid
} {0 {{one two} one {one two} three {one two} two}}


do_catchsql_test 1.5 {
  SELECT * FROM t1 ORDER BY rank(x'0100000001000000') DESC, rowid
} {1 {invalid matchinfo blob passed to function rank()}}





finish_test









>
|
|
|
>
>
>
>
|
<

>
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

68
69
  SELECT * FROM t1 ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
} {1 {invalid matchinfo blob passed to function rank()}}

do_catchsql_test 1.4 {
  SELECT * FROM t1 ORDER BY rank(x'0000000000000000') DESC, rowid
} {0 {{one two} one {one two} three {one two} two}}

if {$tcl_platform(byteOrder)=="littleEndian"} {
  do_catchsql_test 1.5le {
    SELECT * FROM t1 ORDER BY rank(x'0100000001000000') DESC, rowid
  } {1 {invalid matchinfo blob passed to function rank()}}
} else {
  do_catchsql_test 1.5be {
    SELECT * FROM t1 ORDER BY rank(x'0000000100000001') DESC, rowid
  } {1 {invalid matchinfo blob passed to function rank()}}
}


finish_test
Changes to test/func6.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 2017-12-16
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
#
# Test cases for the sqlite_unsupported_offset() function.
#
# Some of the tests in this file depend on the exact placement of content
# within b-tree pages.  Such placement is at the implementations discretion,
# and so it is possible for results to change from one release to the next.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 2017-12-16
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
#
# Test cases for the sqlite_offset() function.
#
# Some of the tests in this file depend on the exact placement of content
# within b-tree pages.  Such placement is at the implementations discretion,
# and so it is possible for results to change from one release to the next.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
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
   INSERT INTO t1(a,b,c,d) SELECT printf('abc%03x',x), x, 1000-x, NULL FROM c;
  CREATE INDEX t1a ON t1(a);
  CREATE INDEX t1bc ON t1(b,c);
  CREATE TABLE t2(x TEXT PRIMARY KEY, y) WITHOUT ROWID;
  INSERT INTO t2(x,y) SELECT a, b FROM t1;
}
do_execsql_test func6-110 {
  SELECT a, sqlite_unsupported_offset(d)/4096 + 1,
            sqlite_unsupported_offset(d)%4096 FROM t1
   ORDER BY rowid LIMIT 2;
} {abc001 2 4084 abc002 2 4069}
do_execsql_test func6-120 {
  SELECT a, typeof(sqlite_unsupported_offset(+a)) FROM t1
   ORDER BY rowid LIMIT 2;
} {abc001 null abc002 null}
do_execsql_test func6-130 {
  SELECT a, sqlite_unsupported_offset(a)/4096+1, 
         sqlite_unsupported_offset(a)%4096
   FROM t1
   ORDER BY a LIMIT 2;
} {abc001 3 4087 abc002 3 4076}
do_execsql_test func6-140 {
  SELECT a, sqlite_unsupported_offset(d)/4096+1, 
         sqlite_unsupported_offset(d)%4096
   FROM t1
   ORDER BY a LIMIT 2;
} {abc001 2 4084 abc002 2 4069}
do_execsql_test func6-150 {
  SELECT a,
         sqlite_unsupported_offset(a)/4096+1, 
         sqlite_unsupported_offset(a)%4096,
         sqlite_unsupported_offset(d)/4096+1, 
         sqlite_unsupported_offset(d)%4096
   FROM t1
   ORDER BY a LIMIT 2;
} {abc001 3 4087 2 4084 abc002 3 4076 2 4069}
do_execsql_test func6-160 {
  SELECT b,
         sqlite_unsupported_offset(b)/4096+1, 
         sqlite_unsupported_offset(b)%4096,
         sqlite_unsupported_offset(c)/4096+1, 
         sqlite_unsupported_offset(c)%4096,
         sqlite_unsupported_offset(d)/4096+1, 
         sqlite_unsupported_offset(d)%4096
   FROM t1
   ORDER BY b LIMIT 2;
} {1 4 4090 4 4090 2 4084 2 4 4081 4 4081 2 4069}


do_execsql_test func6-200 {
  SELECT y, sqlite_unsupported_offset(y)/4096+1,
         sqlite_unsupported_offset(y)%4096
   FROM t2
   ORDER BY x LIMIT 2;
} {1 5 4087 2 5 4076}

finish_test







|
|



|



|
|




|
|





|
|
|
|





|
|
|
|
|
|






|
|





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
   INSERT INTO t1(a,b,c,d) SELECT printf('abc%03x',x), x, 1000-x, NULL FROM c;
  CREATE INDEX t1a ON t1(a);
  CREATE INDEX t1bc ON t1(b,c);
  CREATE TABLE t2(x TEXT PRIMARY KEY, y) WITHOUT ROWID;
  INSERT INTO t2(x,y) SELECT a, b FROM t1;
}
do_execsql_test func6-110 {
  SELECT a, sqlite_offset(d)/4096 + 1,
            sqlite_offset(d)%4096 FROM t1
   ORDER BY rowid LIMIT 2;
} {abc001 2 4084 abc002 2 4069}
do_execsql_test func6-120 {
  SELECT a, typeof(sqlite_offset(+a)) FROM t1
   ORDER BY rowid LIMIT 2;
} {abc001 null abc002 null}
do_execsql_test func6-130 {
  SELECT a, sqlite_offset(a)/4096+1, 
         sqlite_offset(a)%4096
   FROM t1
   ORDER BY a LIMIT 2;
} {abc001 3 4087 abc002 3 4076}
do_execsql_test func6-140 {
  SELECT a, sqlite_offset(d)/4096+1, 
         sqlite_offset(d)%4096
   FROM t1
   ORDER BY a LIMIT 2;
} {abc001 2 4084 abc002 2 4069}
do_execsql_test func6-150 {
  SELECT a,
         sqlite_offset(a)/4096+1, 
         sqlite_offset(a)%4096,
         sqlite_offset(d)/4096+1, 
         sqlite_offset(d)%4096
   FROM t1
   ORDER BY a LIMIT 2;
} {abc001 3 4087 2 4084 abc002 3 4076 2 4069}
do_execsql_test func6-160 {
  SELECT b,
         sqlite_offset(b)/4096+1, 
         sqlite_offset(b)%4096,
         sqlite_offset(c)/4096+1, 
         sqlite_offset(c)%4096,
         sqlite_offset(d)/4096+1, 
         sqlite_offset(d)%4096
   FROM t1
   ORDER BY b LIMIT 2;
} {1 4 4090 4 4090 2 4084 2 4 4081 4 4081 2 4069}


do_execsql_test func6-200 {
  SELECT y, sqlite_offset(y)/4096+1,
         sqlite_offset(y)%4096
   FROM t2
   ORDER BY x LIMIT 2;
} {1 5 4087 2 5 4076}

finish_test
Changes to test/hook.test.
901
902
903
904
905
906
907



















































908
909
910
} {
  INSERT main t3 1 1 0 {} 1
}
do_execsql_test 10.2 { SELECT * FROM t3 } {{} 1}
do_preupdate_test 10.3 {
  DELETE FROM t3 WHERE b=1
} {DELETE main t3 1 1 0 {} 1}





















































finish_test







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



901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
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
} {
  INSERT main t3 1 1 0 {} 1
}
do_execsql_test 10.2 { SELECT * FROM t3 } {{} 1}
do_preupdate_test 10.3 {
  DELETE FROM t3 WHERE b=1
} {DELETE main t3 1 1 0 {} 1}

#-------------------------------------------------------------------------
# Test that the "update" hook is not fired for operations on the 
# sqlite_stat1 table performed by ANALYZE, even if a pre-update hook is
# registered.
ifcapable analyze {
  reset_db
  do_execsql_test 11.1 {
    CREATE TABLE t1(a, b);
    CREATE INDEX idx1 ON t1(a);
    CREATE INDEX idx2 ON t1(b);

    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
    INSERT INTO t1 VALUES(5, 6);
    INSERT INTO t1 VALUES(7, 8);
  }

  db preupdate hook preupdate_cb
  db update_hook update_cb

  proc preupdate_cb {args} { lappend ::res "preupdate" $args }
  proc update_cb {args} { lappend ::res "update" $args }

  set ::res [list]
  do_test 11.2 {
    execsql ANALYZE
    set ::res
  } [list {*}{
    preupdate {INSERT main sqlite_stat1 1 1}
    preupdate {INSERT main sqlite_stat1 2 2}
  }]

  do_execsql_test 11.3 {
    INSERT INTO t1 VALUES(9, 10);
    INSERT INTO t1 VALUES(11, 12);
    INSERT INTO t1 VALUES(13, 14);
    INSERT INTO t1 VALUES(15, 16);
  }

  set ::res [list]
  do_test 11.4 {
    execsql ANALYZE
    set ::res
  } [list {*}{
    preupdate {DELETE main sqlite_stat1 1 1}
    preupdate {DELETE main sqlite_stat1 2 2}
    preupdate {INSERT main sqlite_stat1 1 1}
    preupdate {INSERT main sqlite_stat1 2 2}
  }]
}


finish_test
Changes to test/icu.test.
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  } {1 {wrong number of arguments to function regexp()}}
  do_catchsql_test icu-5.3 { 
    SELECT regexp('a[abc]c.*', 'abc', 'c') 
  } {1 {wrong number of arguments to function regexp()}}
  do_catchsql_test icu-5.4 { 
    SELECT 'abc' REGEXP 'a[abc]c.*'
  } {0 1}
  do_catchsql_test icu-5.4 {SELECT 'abc' REGEXP }   {1 {near " ": syntax error}}
  do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}}
 
  do_malloc_test icu-6.10 -sqlbody {
    SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
  }
}

finish_test







|
|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  } {1 {wrong number of arguments to function regexp()}}
  do_catchsql_test icu-5.3 { 
    SELECT regexp('a[abc]c.*', 'abc', 'c') 
  } {1 {wrong number of arguments to function regexp()}}
  do_catchsql_test icu-5.4 { 
    SELECT 'abc' REGEXP 'a[abc]c.*'
  } {0 1}
  do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP }   {1 {incomplete input}}
  do_catchsql_test icu-5.6 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}}
 
  do_malloc_test icu-6.10 -sqlbody {
    SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
  }
}

finish_test
Changes to test/indexexpr1.test.
408
409
410
411
412
413
414












415
416
do_execsql_test indexexpr1-1500 {
  CREATE TABLE t1500(a INT PRIMARY KEY, b INT UNIQUE);
  CREATE INDEX t1500ab ON t1500(a*b);
  INSERT INTO t1500(a,b) VALUES(1,2);
  REPLACE INTO t1500(a,b) VALUES(1,3);  -- formerly caused assertion fault
  SELECT * FROM t1500;
} {1 3}













finish_test







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


408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
do_execsql_test indexexpr1-1500 {
  CREATE TABLE t1500(a INT PRIMARY KEY, b INT UNIQUE);
  CREATE INDEX t1500ab ON t1500(a*b);
  INSERT INTO t1500(a,b) VALUES(1,2);
  REPLACE INTO t1500(a,b) VALUES(1,3);  -- formerly caused assertion fault
  SELECT * FROM t1500;
} {1 3}

# 2018-01-03 OSSFuzz discovers another test case for the same problem
# above.
#
do_execsql_test indexexpr-1510 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(a PRIMARY KEY,b UNIQUE);
  REPLACE INTO t1 VALUES(2, 1);
  REPLACE INTO t1 SELECT 6,1;
  CREATE INDEX t1aa ON t1(a-a);
  REPLACE INTO t1 SELECT a, randomblob(a) FROM t1
} {}

finish_test
Changes to test/ioerr.test.
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

# Test handling of IO errors that occur while rolling back hot journal
# files.
#
# These tests can't be run on windows because the windows version of 
# SQLite holds a mandatory exclusive lock on journal files it has open.
#
if {$tcl_platform(platform)!="windows"} {
  do_ioerr_test ioerr-7 -tclprep {
    db close
    sqlite3 db2 test2.db
    db2 eval {
      PRAGMA synchronous = 0;
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES(1, 2);







|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

# Test handling of IO errors that occur while rolling back hot journal
# files.
#
# These tests can't be run on windows because the windows version of 
# SQLite holds a mandatory exclusive lock on journal files it has open.
#
if {$tcl_platform(platform)!="windows" && ![atomic_batch_write test.db]} {
  do_ioerr_test ioerr-7 -tclprep {
    db close
    sqlite3 db2 test2.db
    db2 eval {
      PRAGMA synchronous = 0;
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES(1, 2);
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  sqlite3 db test.db
} -sqlbody {
  SELECT c FROM t1;
}

# For test coverage: Cause an IO error whilst reading the master-journal
# name from a journal file.
if {$tcl_platform(platform)=="unix"} {
  do_ioerr_test ioerr-9 -ckrefcount true -tclprep {
    execsql {
      CREATE TABLE t1(a,b,c);
      INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2);
      BEGIN;
      INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2);
    }







|







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  sqlite3 db test.db
} -sqlbody {
  SELECT c FROM t1;
}

# For test coverage: Cause an IO error whilst reading the master-journal
# name from a journal file.
if {$tcl_platform(platform)=="unix" && [atomic_batch_write test.db]==0} {
  do_ioerr_test ioerr-9 -ckrefcount true -tclprep {
    execsql {
      CREATE TABLE t1(a,b,c);
      INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2);
      BEGIN;
      INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2);
    }
Changes to test/journal1.test.
18
19
20
21
22
23
24



25


26
27
28
29
30
31
32

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# These tests will not work on windows because windows uses
# manditory file locking which breaks the copy_file command.
#



if {$tcl_platform(platform)=="windows"} {


  finish_test
  return
}

# Create a smaple database
#
do_test journal1-1.1 {







>
>
>
|
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# These tests will not work on windows because windows uses
# manditory file locking which breaks the copy_file command.
#
# Or with atomic_batch_write systems, as journal files are
# not created.
#
if {$tcl_platform(platform)=="windows"
 || [atomic_batch_write test.db]
} {
  finish_test
  return
}

# Create a smaple database
#
do_test journal1-1.1 {
Changes to test/journal3.test.
16
17
18
19
20
21
22
23


24
25
26
27
28
29
30
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl

#-------------------------------------------------------------------------
# If a connection is required to create a journal file, it creates it with 
# the same file-system permissions as the database file itself. Test this.
#
if {$::tcl_platform(platform) == "unix"} {



  # Changed on 2012-02-13:  umask is deliberately ignored for -wal, -journal,
  # and -shm files.
  #set umask [exec /bin/sh -c umask]
  faultsim_delete_and_reopen
  do_test journal3-1.1 { execsql { CREATE TABLE tx(y, z) } } {}








|
>
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl

#-------------------------------------------------------------------------
# If a connection is required to create a journal file, it creates it with 
# the same file-system permissions as the database file itself. Test this.
#
if {$::tcl_platform(platform) == "unix"
 && [atomic_batch_write test.db]==0
} {

  # Changed on 2012-02-13:  umask is deliberately ignored for -wal, -journal,
  # and -shm files.
  #set umask [exec /bin/sh -c umask]
  faultsim_delete_and_reopen
  do_test journal3-1.1 { execsql { CREATE TABLE tx(y, z) } } {}

Changes to test/jrnlmode.test.
298
299
300
301
302
303
304

305
306
307
308
309
310
311
  integrity_check jrnlmode-4.5
}

#------------------------------------------------------------------------
# The following test caes, jrnlmode-5.*, test the journal_size_limit
# pragma.
ifcapable pragma {

  db close
  forcedelete test.db test2.db test3.db
  sqlite3 db test.db

  do_test jrnlmode-5.1 {
    execsql {pragma page_size=1024}
    execsql {pragma journal_mode=persist}







>







298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  integrity_check jrnlmode-4.5
}

#------------------------------------------------------------------------
# The following test caes, jrnlmode-5.*, test the journal_size_limit
# pragma.
ifcapable pragma {
if {[atomic_batch_write test.db]==0} {
  db close
  forcedelete test.db test2.db test3.db
  sqlite3 db test.db

  do_test jrnlmode-5.1 {
    execsql {pragma page_size=1024}
    execsql {pragma journal_mode=persist}
450
451
452
453
454
455
456
457

458

459
460
461
462
463
464
465
    expr {[file size test.db-journal] > 1024}
  } {1}
  do_test jrnlmode-5.22 {
    execsql COMMIT
    list [file exists test.db-journal] [file size test.db-journal]
  } {1 0}
}


ifcapable pragma {

  # These tests are not run as part of the "journaltest" permutation,
  # as the test_journal.c layer is incompatible with in-memory journaling.
  if {[permutation] ne "journaltest"} {

    do_test jrnlmode-6.1 {
      execsql {
        PRAGMA journal_mode = truncate;







|
>

>







451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
    expr {[file size test.db-journal] > 1024}
  } {1}
  do_test jrnlmode-5.22 {
    execsql COMMIT
    list [file exists test.db-journal] [file size test.db-journal]
  } {1 0}
}
}

ifcapable pragma {
if {[atomic_batch_write test.db]==0} {
  # These tests are not run as part of the "journaltest" permutation,
  # as the test_journal.c layer is incompatible with in-memory journaling.
  if {[permutation] ne "journaltest"} {

    do_test jrnlmode-6.1 {
      execsql {
        PRAGMA journal_mode = truncate;
502
503
504
505
506
507
508

509
510
511
512
513
514
515
      execsql {
        PRAGMA journal_mode = DELETE;
        BEGIN IMMEDIATE; INSERT INTO t4 VALUES(1,2); COMMIT;
      }
      file exists test.db-journal
    } {0}
  }

}

ifcapable pragma {
  catch { db close }
  do_test jrnlmode-7.1 {
    foreach f [glob -nocomplain test.db*] { forcedelete $f }
    sqlite3 db test.db







>







505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
      execsql {
        PRAGMA journal_mode = DELETE;
        BEGIN IMMEDIATE; INSERT INTO t4 VALUES(1,2); COMMIT;
      }
      file exists test.db-journal
    } {0}
  }
}
}

ifcapable pragma {
  catch { db close }
  do_test jrnlmode-7.1 {
    foreach f [glob -nocomplain test.db*] { forcedelete $f }
    sqlite3 db test.db
Changes to test/jrnlmode2.test.
13
14
15
16
17
18
19





20
21
22
23
24
25
26
set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable {!pager_pragmas} {
  finish_test
  return
}






#-------------------------------------------------------------------------
# The tests in this file check that the following two bugs (both now fixed)
# do not reappear.
#
# jrnlmode2-1.*: Demonstrate bug #3745:
#







>
>
>
>
>







13
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

ifcapable {!pager_pragmas} {
  finish_test
  return
}

if {[atomic_batch_write test.db]} {
  finish_test
  return
}

#-------------------------------------------------------------------------
# The tests in this file check that the following two bugs (both now fixed)
# do not reappear.
#
# jrnlmode2-1.*: Demonstrate bug #3745:
#
Changes to test/lock4.test.
12
13
14
15
16
17
18








19
20
21
22
23
24
25
# focus of this script is database locks.
#
# $Id: lock4.test,v 1.10 2009/05/06 00:52:41 drh Exp $


set testdir [file dirname $argv0]
source $testdir/tester.tcl









do_not_use_codec

# Initialize the test.db database so that it is non-empty
#
do_test lock4-1.1 {
  db eval {







>
>
>
>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# focus of this script is database locks.
#
# $Id: lock4.test,v 1.10 2009/05/06 00:52:41 drh Exp $


set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[atomic_batch_write test.db]} {
  # This test uses two processes, one of which blocks until the other
  # creates a *-journal file. Which doesn't work if atomic writes are
  # available.
  finish_test
  return
}

do_not_use_codec

# Initialize the test.db database so that it is non-empty
#
do_test lock4-1.1 {
  db eval {
Changes to test/main.test.
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  catchsql {select 123/*/*2}
} {0 123}
do_test main-3.2.28 {
  catchsql {select 123/**/*2}
} {0 246}
do_test main-3.2.29 {
  catchsql {select 123/}
} {1 {near "/": syntax error}}
do_test main-3.2.30 {
  catchsql {select 123--5}
} {0 123}


do_test main-3.3 {
  catch {db close}







|







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  catchsql {select 123/*/*2}
} {0 123}
do_test main-3.2.28 {
  catchsql {select 123/**/*2}
} {0 246}
do_test main-3.2.29 {
  catchsql {select 123/}
} {1 {incomplete input}}
do_test main-3.2.30 {
  catchsql {select 123--5}
} {0 123}


do_test main-3.3 {
  catch {db close}
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
do_test main-3.4 {
  set v [catch {execsql {create bogus}} msg]
  lappend v $msg
} {1 {near "bogus": syntax error}}
do_test main-3.5 {
  set v [catch {execsql {create}} msg]
  lappend v $msg
} {1 {near "create": syntax error}}
do_test main-3.6 {
  catchsql {SELECT 'abc' + #9}
} {1 {near "#9": syntax error}}

# The following test-case tests the linked list code used to manage
# sqlite3_vfs structures.
if {$::tcl_platform(platform)=="unix" 







|







463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
do_test main-3.4 {
  set v [catch {execsql {create bogus}} msg]
  lappend v $msg
} {1 {near "bogus": syntax error}}
do_test main-3.5 {
  set v [catch {execsql {create}} msg]
  lappend v $msg
} {1 {incomplete input}}
do_test main-3.6 {
  catchsql {SELECT 'abc' + #9}
} {1 {near "#9": syntax error}}

# The following test-case tests the linked list code used to manage
# sqlite3_vfs structures.
if {$::tcl_platform(platform)=="unix" 
Changes to test/malloc.test.
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
    }} err]
    if {$rc && $err!="no such table: t1"} {
      error $err
    }
  }
}

if {$tcl_platform(platform)!="windows"} {
  do_malloc_test 14 -tclprep {
    catch {db close}
    sqlite3 db2 test2.db
    sqlite3_extended_result_codes db2 1
    db2 eval {
      PRAGMA journal_mode = DELETE;    /* For inmemory_journal permutation */
      PRAGMA synchronous = 0;







|







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
    }} err]
    if {$rc && $err!="no such table: t1"} {
      error $err
    }
  }
}

if {$tcl_platform(platform)!="windows" && [atomic_batch_write test.db]==0} {
  do_malloc_test 14 -tclprep {
    catch {db close}
    sqlite3 db2 test2.db
    sqlite3_extended_result_codes db2 1
    db2 eval {
      PRAGMA journal_mode = DELETE;    /* For inmemory_journal permutation */
      PRAGMA synchronous = 0;
Changes to test/malloc3.test.
22
23
24
25
26
27
28











29
30
31
32
33
34
35
# Only run these tests if memory debugging is turned on.
#
if {!$MEMDEBUG} {
   puts "Skipping malloc3 tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}













# Do not run these tests with an in-memory journal.
#
# In the pager layer, if an IO or OOM error occurs during a ROLLBACK, or
# when flushing a page to disk due to cache-stress, the pager enters an
# "error state". The only way out of the error state is to unlock the







>
>
>
>
>
>
>
>
>
>
>







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
# Only run these tests if memory debugging is turned on.
#
if {!$MEMDEBUG} {
   puts "Skipping malloc3 tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}

# Do not run these tests if F2FS batch writes are supported. In this case,
# it is possible for a single DML statement in an implicit transaction
# to fail with SQLITE_NOMEM, but for the transaction to still end up
# committed to disk. Which confuses the tests in this module.
#
if {[atomic_batch_write test.db]} {
   puts "Skipping malloc3 tests: atomic-batch support"
   finish_test
   return
}


# Do not run these tests with an in-memory journal.
#
# In the pager layer, if an IO or OOM error occurs during a ROLLBACK, or
# when flushing a page to disk due to cache-stress, the pager enters an
# "error state". The only way out of the error state is to unlock the
Changes to test/misc7.test.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# $Id: misc7.test,v 1.29 2009/07/16 18:21:18 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


if {[clang_sanitize_address]==0} {
  do_test misc7-1-misuse {
    c_misuse_test
  } {}
}








>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# $Id: misc7.test,v 1.29 2009/07/16 18:21:18 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix misc7

if {[clang_sanitize_address]==0} {
  do_test misc7-1-misuse {
    c_misuse_test
  } {}
}

38
39
40
41
42
43
44

45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
    sqlite3 db2 ./mydir
  } msg]
  list $rc $msg
} {1 {unable to open database file}}

# Try to open a file with a directory where its journal file should be.
#

do_test misc7-5 {
  delete_file mydir
  file mkdir mydir-journal
  sqlite3 db2 ./mydir
  catchsql {
    CREATE TABLE abc(a, b, c);
  } db2
} {1 {unable to open database file}}
db2 close


#--------------------------------------------------------------------
# The following tests, misc7-6.* test the libraries behaviour when
# it cannot open a file. To force this condition, we use up all the
# file-descriptors before running sqlite. This probably only works
# on unix.
#







>
|
|
|
|
|
|
|
|
|
>







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
    sqlite3 db2 ./mydir
  } msg]
  list $rc $msg
} {1 {unable to open database file}}

# Try to open a file with a directory where its journal file should be.
#
if {[atomic_batch_write test.db]==0} {
  do_test misc7-5 {
    delete_file mydir
    file mkdir mydir-journal
    sqlite3 db2 ./mydir
    catchsql {
      CREATE TABLE abc(a, b, c);
    } db2
  } {1 {unable to open database file}}
  db2 close
}

#--------------------------------------------------------------------
# The following tests, misc7-6.* test the libraries behaviour when
# it cannot open a file. To force this condition, we use up all the
# file-descriptors before running sqlite. This probably only works
# on unix.
#
514
515
516
517
518
519
520


521










522
523




524



















525
  puts $fd [string repeat abc 1000]
  close $fd
  catchsql { SELECT * FROM t1 }
} {1 {attempt to write a readonly database}}
do_test misc7-22.4 { 
  sqlite3_extended_errcode db
} SQLITE_READONLY_ROLLBACK













db close
forcedelete test.db
























finish_test







>
>

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

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
  puts $fd [string repeat abc 1000]
  close $fd
  catchsql { SELECT * FROM t1 }
} {1 {attempt to write a readonly database}}
do_test misc7-22.4 { 
  sqlite3_extended_errcode db
} SQLITE_READONLY_ROLLBACK
catch { db close }
forcedelete test.db

if {$::tcl_platform(platform)=="unix"
 && [atomic_batch_write test.db]==0
} {
  reset_db
  do_execsql_test 23.0 {
    CREATE TABLE t1(x, y);
    INSERT INTO t1 VALUES(1, 2);
  }
  
  do_test 23.1 {
    db close
    forcedelete tst
    file mkdir tst
    forcecopy test.db tst/test.db
    file attributes tst -permissions r-xr-xr-x
  } {}
  
  sqlite3 db tst/test.db
  do_execsql_test 23.2 {
    SELECT * FROM t1;
  } {1 2}
  
  do_catchsql_test 23.3 {
    INSERT INTO t1 VALUES(3, 4);
  } {1 {attempt to write a readonly database}}
  
  do_test 23.4 {
    sqlite3_extended_errcode db
  } {SQLITE_READONLY_DIRECTORY}
  
  do_test 23.5 {
    db close
    forcedelete tst
  } {}
}

finish_test
Changes to test/ossfuzz.c.
156
157
158
159
160
161
162



163
164
165
166
167
168
169
  /* Remaining bits of the selector determine a limit on the number of
  ** output rows */
  execCnt = uSelector + 1;

  /* Run the SQL.  The sqlite_exec() interface expects a zero-terminated
  ** string, so make a copy. */
  zSql = sqlite3_mprintf("%.*s", (int)size, data);



  sqlite3_exec(cx.db, zSql, exec_handler, (void*)&execCnt, &zErrMsg);

  /* Show any errors */
  if( (mDebug & FUZZ_SHOW_ERRORS)!=0 && zErrMsg ){
    printf("Error: %s\n", zErrMsg);
  }








>
>
>







156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  /* Remaining bits of the selector determine a limit on the number of
  ** output rows */
  execCnt = uSelector + 1;

  /* Run the SQL.  The sqlite_exec() interface expects a zero-terminated
  ** string, so make a copy. */
  zSql = sqlite3_mprintf("%.*s", (int)size, data);
#ifndef SQLITE_OMIT_COMPLETE
  sqlite3_complete(zSql);
#endif
  sqlite3_exec(cx.db, zSql, exec_handler, (void*)&execCnt, &zErrMsg);

  /* Show any errors */
  if( (mDebug & FUZZ_SHOW_ERRORS)!=0 && zErrMsg ){
    printf("Error: %s\n", zErrMsg);
  }

Changes to test/pager1.test.
12
13
14
15
16
17
18





19
20
21
22
23
24
25

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl
set testprefix pager1






# Do not use a codec for tests in this file, as the database file is
# manipulated directly using tcl scripts (using the [hexio_write] command).
#
do_not_use_codec

#







>
>
>
>
>







12
13
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
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl
set testprefix pager1

if {[atomic_batch_write test.db]} {
  finish_test
  return
}

# Do not use a codec for tests in this file, as the database file is
# manipulated directly using tcl scripts (using the [hexio_write] command).
#
do_not_use_codec

#
Changes to test/pager3.test.
12
13
14
15
16
17
18




19
20
21
22
23
24
25

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl






foreach {tn sql res j} {
  1 "PRAGMA journal_mode = DELETE"  delete        0
  2 "CREATE TABLE t1(a, b)"         {}            0
  3 "PRAGMA locking_mode=EXCLUSIVE" {exclusive}   0
  4 "INSERT INTO t1 VALUES(1, 2)"   {}            1
  5 "PRAGMA locking_mode=NORMAL"    {normal}      1







>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

if {[atomic_batch_write test.db]} {
  finish_test
  return
}

foreach {tn sql res j} {
  1 "PRAGMA journal_mode = DELETE"  delete        0
  2 "CREATE TABLE t1(a, b)"         {}            0
  3 "PRAGMA locking_mode=EXCLUSIVE" {exclusive}   0
  4 "INSERT INTO t1 VALUES(1, 2)"   {}            1
  5 "PRAGMA locking_mode=NORMAL"    {normal}      1
Changes to test/pagerfault.test.
1199
1200
1201
1202
1203
1204
1205

1206
1207
1208
1209
1210
1211

1212
1213
1214
1215
1216
1217
1218
  }
} -test {
  faultsim_test_result {0 {}}

  set contents [db eval {SELECT * FROM t1}]
  if {$contents != "1 2"} { error "Bad database contents ($contents)" }


  set sz [file size test.db]
  if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { 
    error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes"
  }
  if {$testrc==0 && $sz!=4096*3} { 
    error "Expected file size to be 12288 bytes - actual size $sz bytes"

  }
} 

do_test pagerfault-27-pre {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {







>
|
|
|
|
|
|
>







1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
  }
} -test {
  faultsim_test_result {0 {}}

  set contents [db eval {SELECT * FROM t1}]
  if {$contents != "1 2"} { error "Bad database contents ($contents)" }

  if {[atomic_batch_write test.db]==0} {
    set sz [file size test.db]
    if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { 
      error "Expected file size 3072 or 12288 bytes - actual size $sz bytes"
    }
    if {$testrc==0 && $sz!=4096*3} { 
      error "Expected file size to be 12288 bytes - actual size $sz bytes"
    }
  }
} 

do_test pagerfault-27-pre {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {
Changes to test/releasetest.tcl.
730
731
732
733
734
735
736



737
738
739
740
741
742
743
#
proc makeCommand { targets makeOpts cflags opts } {
  set result [list trace_cmd exec]
  if {$::MSVC} {
    set nmakeDir [file nativename $::SRCDIR]
    set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]]
    lappend result nmake /f $nmakeFile TOP=$nmakeDir



    if {[regexp {USE_STDCALL=1} $cflags]} {
      lappend result USE_STDCALL=1
    }
  } else {
    lappend result make
  }
  foreach makeOpt $makeOpts {







>
>
>







730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
#
proc makeCommand { targets makeOpts cflags opts } {
  set result [list trace_cmd exec]
  if {$::MSVC} {
    set nmakeDir [file nativename $::SRCDIR]
    set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]]
    lappend result nmake /f $nmakeFile TOP=$nmakeDir
    set tclDir [file nativename [file normalize \
        [file dirname [file dirname [info nameofexecutable]]]]]
    lappend result "TCLDIR=$tclDir"
    if {[regexp {USE_STDCALL=1} $cflags]} {
      lappend result USE_STDCALL=1
    }
  } else {
    lappend result make
  }
  foreach makeOpt $makeOpts {
Changes to test/rollback.test.
79
80
81
82
83
84
85

86
87
88
89
90
91
92
  sqlite3_finalize $STMT
} {SQLITE_OK}

if {$tcl_platform(platform) == "unix" 
 && [permutation] ne "onefile"
 && [permutation] ne "inmemory_journal"
 && [permutation] ne "atomic-batch-write"

} {
  do_test rollback-2.1 {
    execsql {
      BEGIN;
      INSERT INTO t3 VALUES('hello world');
    }
    forcecopy test.db testA.db







>







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  sqlite3_finalize $STMT
} {SQLITE_OK}

if {$tcl_platform(platform) == "unix" 
 && [permutation] ne "onefile"
 && [permutation] ne "inmemory_journal"
 && [permutation] ne "atomic-batch-write"
 && [atomic_batch_write test.db]==0
} {
  do_test rollback-2.1 {
    execsql {
      BEGIN;
      INSERT INTO t3 VALUES('hello world');
    }
    forcecopy test.db testA.db
Changes to test/rowvalue.test.
389
390
391
392
393
394
395













































396
397
  UPDATE t16c SET a=a WHERE a=3;
  SELECT * FROM t16c;
} {
  1 C B A D
  2 z y x w
  3 i ii iii iv
}














































finish_test







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


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
  UPDATE t16c SET a=a WHERE a=3;
  SELECT * FROM t16c;
} {
  1 C B A D
  2 z y x w
  3 i ii iii iv
}

do_execsql_test 17.0 {
  CREATE TABLE b1(a, b);
  CREATE TABLE b2(x);
}

do_execsql_test 17.1 {
  SELECT * FROM b2 CROSS JOIN b1 
  WHERE b2.x=b1.a AND (b1.a, 2) 
  IN (VALUES(1, 2));
} {}

do_execsql_test 18.0 {
  CREATE TABLE b3 ( a, b, PRIMARY KEY (a, b) );
  CREATE TABLE b4 ( a );
  CREATE TABLE b5 ( a, b );
  INSERT INTO b3 VALUES (1, 1), (1, 2);
  INSERT INTO b4 VALUES (1);
  INSERT INTO b5 VALUES (1, 1), (1, 2);
}

do_execsql_test 18.1 {
  SELECT * FROM b3 WHERE (SELECT b3.a, b3.b) IN ( SELECT a, b FROM b5 )
} {1 1 1 2}
do_execsql_test 18.2 {
  SELECT * FROM b3 WHERE (VALUES(b3.a, b3.b)) IN ( SELECT a, b FROM b5 );
} {1 1 1 2}
do_execsql_test 18.3 {
  SELECT * FROM b3 WHERE (b3.a, b3.b) IN ( SELECT a, b FROM b5 ); 
} {1 1 1 2}
do_execsql_test 18.4 {
  SELECT * FROM b3 JOIN b4 ON b4.a = b3.a
  WHERE (SELECT b3.a, b3.b) IN ( SELECT a, b FROM b5 ); 
} {1 1 1 1 2 1}
do_execsql_test 18.5 {
  SELECT * FROM b3 JOIN b4 ON b4.a = b3.a
  WHERE (VALUES(b3.a, b3.b)) IN ( SELECT a, b FROM b5 ); 
} {1 1 1 1 2 1}
do_execsql_test 18.6 {
  SELECT * FROM b3 JOIN b4 ON b4.a = b3.a
  WHERE (b3.a, b3.b) IN ( SELECT a, b FROM b5 ); 
} {1 1 1 1 2 1}

 
finish_test

finish_test
Changes to test/select1.test.
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  }} msg]
  lappend v $msg
} {1 {near "WHERE": syntax error}}
} ;# ifcapable compound
do_test select1-7.3 {
  set v [catch {execsql {SELECT f1 FROM test1 as 'hi', test2 as}} msg]
  lappend v $msg
} {1 {near "as": syntax error}}
do_test select1-7.4 {
  set v [catch {execsql {
     SELECT f1 FROM test1 ORDER BY;
  }} msg]
  lappend v $msg
} {1 {near ";": syntax error}}
do_test select1-7.5 {







|







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  }} msg]
  lappend v $msg
} {1 {near "WHERE": syntax error}}
} ;# ifcapable compound
do_test select1-7.3 {
  set v [catch {execsql {SELECT f1 FROM test1 as 'hi', test2 as}} msg]
  lappend v $msg
} {1 {incomplete input}}
do_test select1-7.4 {
  set v [catch {execsql {
     SELECT f1 FROM test1 ORDER BY;
  }} msg]
  lappend v $msg
} {1 {near ";": syntax error}}
do_test select1-7.5 {
Changes to test/selectG.test.
32
33
34
35
36
37
38




















39
  append sql "($i);"
  set microsec [lindex [time {db eval $sql}] 0]
  db eval {
    SELECT count(x), sum(x), avg(x), $microsec<10000000 FROM t1;
  }
} {100000 5000050000 50000.5 1}
  




















finish_test







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

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
  append sql "($i);"
  set microsec [lindex [time {db eval $sql}] 0]
  db eval {
    SELECT count(x), sum(x), avg(x), $microsec<10000000 FROM t1;
  }
} {100000 5000050000 50000.5 1}
  
# 2018-01-14.  A 100K-entry VALUES clause within a scalar expression does
# not cause processor stack overflow.
#
do_test 110 {
  set sql "SELECT (VALUES"
  for {set i 1} {$i<100000} {incr i} {
    append sql "($i),"
  }
  append sql "($i));"
  db eval $sql
} {1}

# Only the left-most term of a multi-valued VALUES within a scalar
# expression is evaluated.
#
do_test 120 {
  set n [llength [split [db eval "explain $sql"] \n]]
  expr {$n<10}
} {1}

finish_test
Changes to test/sharedA.test.
14
15
16
17
18
19
20





21
22
23
24
25
26
27


set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {[run_thread_tests]==0} { finish_test ; return }
db close
set ::testprefix sharedA






set ::enable_shared_cache [sqlite3_enable_shared_cache 1]

#-------------------------------------------------------------------------
#
do_test 0.1 {
  sqlite3 db1 test.db







>
>
>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {[run_thread_tests]==0} { finish_test ; return }
db close
set ::testprefix sharedA

if {[atomic_batch_write test.db]} {
  finish_test
  return
}

set ::enable_shared_cache [sqlite3_enable_shared_cache 1]

#-------------------------------------------------------------------------
#
do_test 0.1 {
  sqlite3 db1 test.db
Changes to test/shell1.test.
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
} {0 {}}
do_test shell1-3.15.2 {
  catchcmd "test.db" ".output FOO"
} {0 {}}
do_test shell1-3.15.3 {
  # too many arguments
  catchcmd "test.db" ".output FOO BAD"
} {1 {Usage: .output FILE}}

# .output stdout         Send output to the screen
do_test shell1-3.16.1 {
  catchcmd "test.db" ".output stdout"
} {0 {}}
do_test shell1-3.16.2 {
  # too many arguments
  catchcmd "test.db" ".output stdout BAD"
} {1 {Usage: .output FILE}}

# .prompt MAIN CONTINUE  Replace the standard prompts
do_test shell1-3.17.1 {
  catchcmd "test.db" ".prompt"
} {0 {}}
do_test shell1-3.17.2 {
  catchcmd "test.db" ".prompt FOO"







|








|







491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
} {0 {}}
do_test shell1-3.15.2 {
  catchcmd "test.db" ".output FOO"
} {0 {}}
do_test shell1-3.15.3 {
  # too many arguments
  catchcmd "test.db" ".output FOO BAD"
} {1 {Usage: .output [-e|-x|FILE]}}

# .output stdout         Send output to the screen
do_test shell1-3.16.1 {
  catchcmd "test.db" ".output stdout"
} {0 {}}
do_test shell1-3.16.2 {
  # too many arguments
  catchcmd "test.db" ".output stdout BAD"
} {1 {Usage: .output [-e|-x|FILE]}}

# .prompt MAIN CONTINUE  Replace the standard prompts
do_test shell1-3.17.1 {
  catchcmd "test.db" ".prompt"
} {0 {}}
do_test shell1-3.17.2 {
  catchcmd "test.db" ".prompt FOO"
Changes to test/shell3.test.
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  catchcmd "foo.db \"CREATE TABLE t1(a); DROP TABLE t1;\""
} {0 {}}
do_test shell3-1.6 {
  catchcmd "foo.db" ".tables"
} {0 {}}
do_test shell3-1.7 {
  catchcmd "foo.db \"CREATE TABLE\""
} {1 {Error: near "TABLE": syntax error}}

#----------------------------------------------------------------------------
#   shell3-2.*: Basic tests for running SQL file from command line.
#

# Run SQL file from command line
do_test shell3-2.1 {







|







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  catchcmd "foo.db \"CREATE TABLE t1(a); DROP TABLE t1;\""
} {0 {}}
do_test shell3-1.6 {
  catchcmd "foo.db" ".tables"
} {0 {}}
do_test shell3-1.7 {
  catchcmd "foo.db \"CREATE TABLE\""
} {1 {Error: incomplete input}}

#----------------------------------------------------------------------------
#   shell3-2.*: Basic tests for running SQL file from command line.
#

# Run SQL file from command line
do_test shell3-2.1 {
92
93
94
95
96
97
98
99
100
101
  catchcmd "foo.db" "CREATE TABLE t1(a); DROP TABLE t1;"
} {0 {}}
do_test shell3-2.6 {
  catchcmd "foo.db" ".tables"
} {0 {}}
do_test shell3-2.7 {
  catchcmd "foo.db" "CREATE TABLE"
} {1 {Error: near line 1: near "TABLE": syntax error}}

finish_test







|


92
93
94
95
96
97
98
99
100
101
  catchcmd "foo.db" "CREATE TABLE t1(a); DROP TABLE t1;"
} {0 {}}
do_test shell3-2.6 {
  catchcmd "foo.db" ".tables"
} {0 {}}
do_test shell3-2.7 {
  catchcmd "foo.db" "CREATE TABLE"
} {1 {Error: near line 1: incomplete input}}

finish_test
Added test/shell8.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
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
# 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.
#
#***********************************************************************
#
# Test the shell tool ".ar" command.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shell8

ifcapable !vtab {
  finish_test; return
}
set CLI [test_find_cli]

# Check to make sure the shell has been compiled with ".archive" support.
#
if {[string match {*unknown command*} [catchcmd :memory: .archive]]} {
  finish_test; return
}

proc populate_dir {dirname spec} {
  # First delete the current tree, if one exists.
  file delete -force $dirname
  
  # Recreate the root of the new tree.
  file mkdir $dirname

  # Add each file to the new tree.
  foreach {f d} $spec {
    set path [file join $dirname $f]
    file mkdir [file dirname $path]
    set fd [open $path w]
    puts -nonewline $fd $d
    close $fd
  }
}

proc dir_to_list {dirname {n -1}} {
  if {$n<0} {set n [llength [file split $dirname]]}

  set res [list]
  foreach f [glob -nocomplain $dirname/*] {
    set mtime [file mtime $f]
    if {$::tcl_platform(platform)!="windows"} {
      set perm [file attributes $f -perm]
    } else {
      set perm 0
    }
    set relpath [file join {*}[lrange [file split $f] $n end]]
    lappend res 
    if {[file isdirectory $f]} {
      lappend res [list $relpath / $mtime $perm]
      lappend res {*}[dir_to_list $f]
    } else {
      set fd [open $f]
      set data [read $fd]
      close $fd
      lappend res [list $relpath $data $mtime $perm]
    }
  }
  lsort $res
}

proc dir_compare {d1 d2} {
  set l1 [dir_to_list $d1]
  set l2 [dir_to_list $d1]
  string compare $l1 $l2
}

foreach {tn tcl} {
  1 {
    set c1 ".ar c ar1"
    set x1 ".ar x"

    set c2 ".ar cC ar1 ."
    set x2 ".ar Cx ar3"

    set c3 ".ar cCf ar1 test_xyz.db ."
    set x3 ".ar Cfx ar3 test_xyz.db"
  }

  2 {
    set c1 ".ar -c ar1"
    set x1 ".ar -x"

    set c2 ".ar -cC ar1 ."
    set x2 ".ar -xC ar3"

    set c3 ".ar -cCar1 -ftest_xyz.db ."
    set x3 ".ar -x -C ar3 -f test_xyz.db"
  }

  3 {
    set c1 ".ar --create ar1"
    set x1 ".ar --extract"

    set c2 ".ar --directory ar1 --create ."
    set x2 ".ar --extract --dir ar3"

    set c3 ".ar --creat --dir ar1 --file test_xyz.db ."
    set x3 ".ar --e  --dir ar3 --f test_xyz.db"
  }

  4 {
    set c1 ".ar --cr ar1"
    set x1 ".ar --e"

    set c2 ".ar -C ar1 -c ."
    set x2 ".ar -x -C ar3"

    set c3 ".ar -c --directory ar1 --file test_xyz.db ."
    set x3 ".ar -x --directory ar3 --file test_xyz.db"
  }
} {
  eval $tcl

  # Populate directory "ar1" with some files.
  #
  populate_dir ar1 {
    file1 "abcd" 
    file2 "efgh"
    dir1/file3 "ijkl"
  }
  set expected [dir_to_list ar1]

  do_test 1.$tn.1 {
    catchcmd test_ar.db $c1
    file delete -force ar1
    catchcmd test_ar.db $x1
    dir_to_list ar1
  } $expected

  do_test 1.$tn.2 {
    file delete -force ar3
    catchcmd test_ar.db $c2
    catchcmd test_ar.db $x2
    dir_to_list ar3
  } $expected

  do_test 1.$tn.3 {
    file delete -force ar3
    file delete -force test_xyz.db
    catchcmd ":memory:" $c3
    catchcmd ":memory:" $x3
    dir_to_list ar3
  } $expected

  # This is a repeat of test 1.$tn.1, except that there is a 2 second 
  # pause between creating the archive and extracting its contents.
  # This is to test that timestamps are set correctly.
  #
  # Because it is slow, only do this for $tn==1.
  if {$tn==1} {
    do_test 1.$tn.1 {
      catchcmd test_ar.db $c1
      file delete -force ar1
      after 2000
      catchcmd test_ar.db $x1
      dir_to_list ar1
    } $expected
  }
}

finish_test



finish_test
Changes to test/stmt.test.
11
12
13
14
15
16
17





18
19
20
21
22
23
24
#
# The tests in this file check that SQLite uses (or does not use) a
# statement journal for various SQL statements.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl






do_test stmt-1.1 {
  execsql { CREATE TABLE t1(a integer primary key, b INTEGER NOT NULL) }
} {}

# The following tests verify the method used for the tests in this file -
# that if a statement journal is required by a statement it is opened and







>
>
>
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#
# The tests in this file check that SQLite uses (or does not use) a
# statement journal for various SQL statements.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[atomic_batch_write test.db]} {
  finish_test
  return
}

do_test stmt-1.1 {
  execsql { CREATE TABLE t1(a integer primary key, b INTEGER NOT NULL) }
} {}

# The following tests verify the method used for the tests in this file -
# that if a statement journal is required by a statement it is opened and
Changes to test/swarmvtab3.test.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
db func openclose_db openclose_db

proc check_dbcache {} {
  set n 0
  for {set i 0} {$i<100} {incr i} {
    set exists [file exists test.db$i]
    if {$exists!=($::dbcache(test.db$i)!=0)} {
      error "inconsistent ::dbcache and disk"
    }
    incr n $exists
  }
  return $n
}

foreach {tn nMaxOpen cvt} {







|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
db func openclose_db openclose_db

proc check_dbcache {} {
  set n 0
  for {set i 0} {$i<100} {incr i} {
    set exists [file exists test.db$i]
    if {$exists!=($::dbcache(test.db$i)!=0)} {
      error "inconsistent ::dbcache and disk ($i) - $exists"
    }
    incr n $exists
  }
  return $n
}

foreach {tn nMaxOpen cvt} {
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
        openclose=[openclose_db],
        maxopen = 1
    )
  }

} {
  execsql { DROP TABLE IF EXISTS s }
  
  do_execsql_test 1.$tn.1 $cvt

  do_execsql_test 1.$tn.2 {
    SELECT b FROM s WHERE a<10;
  } {0 1 2 3 4 5 6 7 8 9}

  do_test 1.$tn.3 { check_dbcache } $nMaxOpen







|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
        openclose=[openclose_db],
        maxopen = 1
    )
  }

} {
  execsql { DROP TABLE IF EXISTS s }

  do_execsql_test 1.$tn.1 $cvt

  do_execsql_test 1.$tn.2 {
    SELECT b FROM s WHERE a<10;
  } {0 1 2 3 4 5 6 7 8 9}

  do_test 1.$tn.3 { check_dbcache } $nMaxOpen
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
db func openclose_db openclose_db

proc check_dbcache {} {
  set n 0
  foreach k [array names ::dbcache] {
    set exists [file exists $k]
    if {$exists!=($::dbcache($k)!=0)} {
      error "inconsistent ::dbcache and disk ($k)"
    }
    incr n $exists
  }
  return $n
}

foreach {tn nMaxOpen cvt} {
  2 5 {
    CREATE VIRTUAL TABLE temp.s USING swarmvtab(
        'SELECT file, tbl, minval, minval, ctx FROM swarm',
        missing=missing_db,
        openclose=openclose_db,
        maxopen=5
    )
  }
} {
  execsql { DROP TABLE IF EXISTS s }
  
  do_execsql_test 1.$tn.1 $cvt

  do_execsql_test 1.$tn.2 {
    SELECT b FROM s WHERE a<10;
  } {0 1 2 3 4 5 6 7 8 9}

  do_test 1.$tn.3 { check_dbcache } $nMaxOpen

  do_execsql_test 1.$tn.4 {
    SELECT b FROM s WHERE (b%10)=0;
  } {0 10 20 30 40 50 60 70 80 90}

  do_test 1.$tn.5 { check_dbcache } $nMaxOpen
}

db close

forcedelete {*}[glob test_remote.db*]

finish_test








|

















|
|

|



|

|



|



>




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
db func openclose_db openclose_db

proc check_dbcache {} {
  set n 0
  foreach k [array names ::dbcache] {
    set exists [file exists $k]
    if {$exists!=($::dbcache($k)!=0)} {
      error "inconsistent ::dbcache and disk ($k) - $exists"
    }
    incr n $exists
  }
  return $n
}

foreach {tn nMaxOpen cvt} {
  2 5 {
    CREATE VIRTUAL TABLE temp.s USING swarmvtab(
        'SELECT file, tbl, minval, minval, ctx FROM swarm',
        missing=missing_db,
        openclose=openclose_db,
        maxopen=5
    )
  }
} {
  execsql { DROP TABLE IF EXISTS s }

  do_execsql_test 3.$tn.1 $cvt

  do_execsql_test 3.$tn.2 {
    SELECT b FROM s WHERE a<10;
  } {0 1 2 3 4 5 6 7 8 9}

  do_test 3.$tn.3 { check_dbcache } $nMaxOpen

  do_execsql_test 3.$tn.4 {
    SELECT b FROM s WHERE (b%10)=0;
  } {0 10 20 30 40 50 60 70 80 90}

  do_test 3.$tn.5 { check_dbcache } $nMaxOpen
}

db close
forcedelete {*}[glob test.db*]
forcedelete {*}[glob test_remote.db*]

finish_test

Changes to test/symlink.test.
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  } 0
  do_test 2.$tn.2 {
    execsql {
      BEGIN;
        INSERT INTO t1 VALUES(1);
    } db2
    file exists test.db-journal
  } 1
  do_test 2.$tn.3 {
    list [file exists test2.db-journal] [file exists test3.db-journal]
  } {0 0}
  do_test 2.$tn.4 {
    execsql {
      COMMIT;
      PRAGMA journal_mode = wal;







|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  } 0
  do_test 2.$tn.2 {
    execsql {
      BEGIN;
        INSERT INTO t1 VALUES(1);
    } db2
    file exists test.db-journal
  } [expr [atomic_batch_write test.db]==0]
  do_test 2.$tn.3 {
    list [file exists test2.db-journal] [file exists test3.db-journal]
  } {0 0}
  do_test 2.$tn.4 {
    execsql {
      COMMIT;
      PRAGMA journal_mode = wal;
Changes to test/sync.test.
21
22
23
24
25
26
27




28
29
30
31
32
33
34
# These tests are only applicable when pager pragma are
# enabled. Also, since every test uses an ATTACHed database, they
# are only run when ATTACH is enabled.
#
ifcapable !pager_pragmas||!attach {
  finish_test
  return




}

set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
  global sqlite_sync_count
  if {$::tcl_platform(platform) == "windows"} {
    incr sqlite_sync_count $adj







>
>
>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# These tests are only applicable when pager pragma are
# enabled. Also, since every test uses an ATTACHed database, they
# are only run when ATTACH is enabled.
#
ifcapable !pager_pragmas||!attach {
  finish_test
  return
}
if {[atomic_batch_write test.db]} {
  finish_test
  return
}

set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
  global sqlite_sync_count
  if {$::tcl_platform(platform) == "windows"} {
    incr sqlite_sync_count $adj
Changes to test/sync2.test.
25
26
27
28
29
30
31

32
33
34
35
36
37
38
ifcapable !pager_pragmas||!attach||!dirsync {
  finish_test
  return
}
if {$::tcl_platform(platform)!="unix" 
  || [permutation] == "journaltest"
  || [permutation] == "inmemory_journal"

} {
  finish_test
  return
}

proc execsql_sync {sql} {
  set s $::sqlite_sync_count







>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
ifcapable !pager_pragmas||!attach||!dirsync {
  finish_test
  return
}
if {$::tcl_platform(platform)!="unix" 
  || [permutation] == "journaltest"
  || [permutation] == "inmemory_journal"
  || [atomic_batch_write test.db] 
} {
  finish_test
  return
}

proc execsql_sync {sql} {
  set s $::sqlite_sync_count
Changes to test/tempdb.test.
12
13
14
15
16
17
18





19
20
21
22
23
24
25
# The focus of this file is in making sure that rolling back
# a statement journal works correctly.
#
# $Id: tempdb.test,v 1.4 2009/06/05 17:09:12 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl






# Use a temporary database.
#
db close
sqlite3 db {}

# Force a statement journal rollback on a database file that







>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# The focus of this file is in making sure that rolling back
# a statement journal works correctly.
#
# $Id: tempdb.test,v 1.4 2009/06/05 17:09:12 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[atomic_batch_write test.db]} {
  finish_test
  return
}

# Use a temporary database.
#
db close
sqlite3 db {}

# Force a statement journal rollback on a database file that
Changes to test/tkt3457.test.
14
15
16
17
18
19
20




21
22
23
24
25
26
27

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {$tcl_platform(platform) != "unix"} {
  finish_test
  return




}

#-----------------------------------------------------------------------
# To roll back a hot-journal file, the application needs read and write 
# permission on the journal file in question. The following tests test
# the outcome of trying to rollback a hot-journal file when this is not
# the case.







>
>
>
>







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

if {$tcl_platform(platform) != "unix"} {
  finish_test
  return
}
if {[atomic_batch_write test.db]} {
  finish_test
  return
}

#-----------------------------------------------------------------------
# To roll back a hot-journal file, the application needs read and write 
# permission on the journal file in question. The following tests test
# the outcome of trying to rollback a hot-journal file when this is not
# the case.
Changes to test/update2.test.
196
197
198
199
200
201
202















203
204

do_test 5.2 {
  catch { array unset A }
  db eval { EXPLAIN UPDATE x1 SET c=c+1 WHERE b='a' } { incr A($opcode) }
  set A(NotExists)
} {1}

















finish_test







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


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

do_test 5.2 {
  catch { array unset A }
  db eval { EXPLAIN UPDATE x1 SET c=c+1 WHERE b='a' } { incr A($opcode) }
  set A(NotExists)
} {1}

#-------------------------------------------------------------------------
do_execsql_test 6.0 {
  CREATE TABLE d1(a,b);
  CREATE INDEX d1b ON d1(a);
  CREATE INDEX d1c ON d1(b);
  INSERT INTO d1 VALUES(1,2);
}

do_execsql_test 6.1 {
  UPDATE d1 SET a = a+2 WHERE a>0 OR b>0;
}

do_execsql_test 6.2 {
  SELECT * FROM d1;
} {3 2}

finish_test
Changes to test/vacuum5.test.
139
140
141
142
143
144
145

146
147
148

149
150
151
152
153
    INSERT INTO t1 SELECT NULL, randomblob(100) FROM s;
  }

  do_execsql_test 3.1 { VACUUM }

  db close
  tvfs delete

  do_test 3.2 {
    lrange $::openfiles 0 4
  } {test.db test.db-journal test.db-journal {} test.db-journal}

} 



finish_test







>
|
|
|
>





139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    INSERT INTO t1 SELECT NULL, randomblob(100) FROM s;
  }

  do_execsql_test 3.1 { VACUUM }

  db close
  tvfs delete
  if {[atomic_batch_write test.db]==0} {
    do_test 3.2 {
      lrange $::openfiles 0 4
    } {test.db test.db-journal test.db-journal {} test.db-journal}
  }
} 



finish_test
Changes to test/wal2.test.
580
581
582
583
584
585
586



587
588

589
590
591
592
593



594
595

596
597
598
599
600
601
602
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 VALUES('Groucho');
  }



  list [file exists test.db-wal] [file exists test.db-journal]
} {0 1}

do_test wal2-6.3.5 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.6 {
  execsql { COMMIT }



  list [file exists test.db-wal] [file exists test.db-journal]
} {0 1}

do_test wal2-6.3.7 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
db close


# This test - wal2-6.4.* - uses a single database connection and the







>
>
>
|
|
>





>
>
>
|
|
>







580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 VALUES('Groucho');
  }
} {}
if {[atomic_batch_write test.db]==0} {
  do_test wal2-6.3.4.1 {
    list [file exists test.db-wal] [file exists test.db-journal]
  } {0 1}
}
do_test wal2-6.3.5 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.6 {
  execsql { COMMIT }
} {}
if {[atomic_batch_write test.db]==0} {
  do_test wal2-6.3.6.1 {
    list [file exists test.db-wal] [file exists test.db-journal]
  } {0 1}
}
do_test wal2-6.3.7 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
db close


# This test - wal2-6.4.* - uses a single database connection and the
Changes to test/walfault.test.
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
  set nRow [db eval {SELECT count(*) FROM abc}]
  if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" }
}

#-------------------------------------------------------------------------
# Test fault-handling when switching out of exclusive-locking mode.
#
do_test walfault-14-pre {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA auto_vacuum = 0;
    PRAGMA journal_mode = WAL;
    BEGIN;
      CREATE TABLE abc(a PRIMARY KEY);
      INSERT INTO abc VALUES(randomblob(1500));
      INSERT INTO abc VALUES(randomblob(1500));
    COMMIT;
  }
  faultsim_save_and_close
} {}
do_faultsim_test walfault-14 -prep {
  faultsim_restore_and_reopen
  execsql {
    SELECT count(*) FROM abc;
    PRAGMA locking_mode = exclusive;
    BEGIN;
      INSERT INTO abc VALUES(randomblob(1500));
    COMMIT;







|












|







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
  set nRow [db eval {SELECT count(*) FROM abc}]
  if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" }
}

#-------------------------------------------------------------------------
# Test fault-handling when switching out of exclusive-locking mode.
#
do_test walfault-15-pre {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA auto_vacuum = 0;
    PRAGMA journal_mode = WAL;
    BEGIN;
      CREATE TABLE abc(a PRIMARY KEY);
      INSERT INTO abc VALUES(randomblob(1500));
      INSERT INTO abc VALUES(randomblob(1500));
    COMMIT;
  }
  faultsim_save_and_close
} {}
do_faultsim_test walfault-15 -prep {
  faultsim_restore_and_reopen
  execsql {
    SELECT count(*) FROM abc;
    PRAGMA locking_mode = exclusive;
    BEGIN;
      INSERT INTO abc VALUES(randomblob(1500));
    COMMIT;
Changes to test/walmode.test.
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56

57
58
59
60
61
62
63
  execsql { PRAGMA page_size = 1024 }
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-1.2 {
  file size test.db
} {1024}


set expected_sync_count 3
if {$::tcl_platform(platform)!="windows"} {
  ifcapable dirsync {
    incr expected_sync_count
  }
}
do_test walmode-1.3 {
  set sqlite_sync_count
} $expected_sync_count


do_test walmode-1.4 {
  file exists test.db-wal
} {0}
do_test walmode-1.5 {
  execsql { CREATE TABLE t1(a, b) }
  file size test.db







>
|
|
|
|
|
|
|
|
|
>







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
  execsql { PRAGMA page_size = 1024 }
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-1.2 {
  file size test.db
} {1024}

if {[atomic_batch_write test.db]==0} {
  set expected_sync_count 3
  if {$::tcl_platform(platform)!="windows"} {
    ifcapable dirsync {
      incr expected_sync_count
    }
  }
  do_test walmode-1.3 {
    set sqlite_sync_count
  } $expected_sync_count
}

do_test walmode-1.4 {
  file exists test.db-wal
} {0}
do_test walmode-1.5 {
  execsql { CREATE TABLE t1(a, b) }
  file size test.db
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

# Test that changing back to journal_mode=persist works.
#
do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }
  execsql { PRAGMA journal_mode = persist }
} {persist}

do_test walmode-4.2 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}

do_test walmode-4.3 {
  execsql { SELECT * FROM t1 }
} {1 2}
do_test walmode-4.4 {
  db close
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }
} {1 2}

do_test walmode-4.5 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}


# Test that nothing goes wrong if a connection is prevented from changing
# from WAL to rollback mode because a second connection has the database
# open. Or from rollback to WAL.
#
do_test walmode-4.6 {
  sqlite3 db2 test.db







>
|
|
|
>








>
|
|
|
>







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

# Test that changing back to journal_mode=persist works.
#
do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }
  execsql { PRAGMA journal_mode = persist }
} {persist}
if {[atomic_batch_write test.db]==0} {
  do_test walmode-4.2 {
    list [file exists test.db-journal] [file exists test.db-wal]
  } {1 0}
}
do_test walmode-4.3 {
  execsql { SELECT * FROM t1 }
} {1 2}
do_test walmode-4.4 {
  db close
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }
} {1 2}
if {[atomic_batch_write test.db]==0} {
  do_test walmode-4.5 {
    list [file exists test.db-journal] [file exists test.db-wal]
  } {1 0}
}

# Test that nothing goes wrong if a connection is prevented from changing
# from WAL to rollback mode because a second connection has the database
# open. Or from rollback to WAL.
#
do_test walmode-4.6 {
  sqlite3 db2 test.db
Changes to test/walro2.test.
257
258
259
260
261
262
263
264
265

266
267
268
269
270
271
272
273
        WITH s(i) AS (
          SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
          )
        INSERT INTO t2 SELECT randomblob(500) FROM s;
        SELECT count(*) FROM t2;
    } 
  } {500}
  do_test $TN.4.2.2 {
    set sz [file size test.db-wal]

    expr {$sz>400000 && $sz<500000}
  } {1}
  do_test $TN.4.2.4 {
    file_control_persist_wal db 1; db close

    copy_to_test2 $bZeroShm
    code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
    sql2 {







<
|
>
|







257
258
259
260
261
262
263

264
265
266
267
268
269
270
271
272
273
        WITH s(i) AS (
          SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
          )
        INSERT INTO t2 SELECT randomblob(500) FROM s;
        SELECT count(*) FROM t2;
    } 
  } {500}

  set sz [file size test.db-wal]
  do_test $TN.4.2.2.(sz=$sz) {
    expr {$sz>400000}
  } {1}
  do_test $TN.4.2.4 {
    file_control_persist_wal db 1; db close

    copy_to_test2 $bZeroShm
    code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
    sql2 {
Changes to test/walthread.test.
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
# two do "journal_mode = DELETE".
#
# Each client returns a string of the form "W w, R r", where W is the 
# number of write-transactions performed using a WAL journal, and D is
# the number of write-transactions performed using a rollback journal.
# For example, "192 w, 185 r".
#

do_thread_test2 walthread-2 -seconds $seconds(walthread-2) -init {
  execsql { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE) }
} -thread RB 2 {

  db close
  set nRun 0
  set nDel 0
  while {[tt_continue]} {
    sqlite3 db test.db
    db busy busyhandler
    db eval { SELECT * FROM sqlite_master }
    catch { db eval { PRAGMA journal_mode = DELETE } }
    db eval {
      BEGIN;
      INSERT INTO t1 VALUES(NULL, randomblob(100+$E(pid)));
    }
    incr nRun 1
    incr nDel [file exists test.db-journal]
    if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
      error "File-system looks bad..."
    }
    db eval COMMIT

    integrity_check
    db close
  }
  list $nRun $nDel
  set {} "[expr $nRun-$nDel] w, $nDel r"

} -thread WAL 2 {
  db close
  set nRun 0
  set nDel 0
  while {[tt_continue]} {
    sqlite3 db test.db
    db busy busyhandler
    db eval { SELECT * FROM sqlite_master }
    catch { db eval { PRAGMA journal_mode = WAL } }
    db eval {
      BEGIN;
      INSERT INTO t1 VALUES(NULL, randomblob(110+$E(pid)));
    }
    incr nRun 1
    incr nDel [file exists test.db-journal]
    if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
      error "File-system looks bad..."
    }
    db eval COMMIT

    integrity_check
    db close
  }
  set {} "[expr $nRun-$nDel] w, $nDel r"

}

do_thread_test walthread-3 -seconds $seconds(walthread-3) -init {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);
    CREATE INDEX i1 ON t1(sum1);







>
|
|
|

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







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
# two do "journal_mode = DELETE".
#
# Each client returns a string of the form "W w, R r", where W is the 
# number of write-transactions performed using a WAL journal, and D is
# the number of write-transactions performed using a rollback journal.
# For example, "192 w, 185 r".
#
if {[atomic_batch_write test.db]==0} {
  do_thread_test2 walthread-2 -seconds $seconds(walthread-2) -init {
    execsql { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE) }
  } -thread RB 2 {

    db close
    set nRun 0
    set nDel 0
    while {[tt_continue]} {
      sqlite3 db test.db
      db busy busyhandler
      db eval { SELECT * FROM sqlite_master }
      catch { db eval { PRAGMA journal_mode = DELETE } }
      db eval {
        BEGIN;
        INSERT INTO t1 VALUES(NULL, randomblob(100+$E(pid)));
      }
      incr nRun 1
      incr nDel [file exists test.db-journal]
      if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
        error "File-system looks bad..."
      }
      db eval COMMIT
  
      integrity_check
      db close
    }
    list $nRun $nDel
    set {} "[expr $nRun-$nDel] w, $nDel r"
  
  } -thread WAL 2 {
    db close
    set nRun 0
    set nDel 0
    while {[tt_continue]} {
      sqlite3 db test.db
      db busy busyhandler
      db eval { SELECT * FROM sqlite_master }
      catch { db eval { PRAGMA journal_mode = WAL } }
      db eval {
        BEGIN;
        INSERT INTO t1 VALUES(NULL, randomblob(110+$E(pid)));
      }
      incr nRun 1
      incr nDel [file exists test.db-journal]
      if {[file exists test.db-journal] + [file exists test.db-wal] != 1} {
        error "File-system looks bad..."
      }
      db eval COMMIT
  
      integrity_check
      db close
    }
    set {} "[expr $nRun-$nDel] w, $nDel r"
  }
}

do_thread_test walthread-3 -seconds $seconds(walthread-3) -init {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);
    CREATE INDEX i1 ON t1(sum1);
Changes to test/with2.test.
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
do_catchsql_test 6.5 {
  WITH x AS (SELECT * FROM t1)
  DELETE FROM t2 WHERE;
} {1 {near ";": syntax error}}

do_catchsql_test 6.6 { 
  WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHERE
} {/1 {near .* syntax error}/}

do_catchsql_test 6.7 { 
  WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHRE 1;
} {/1 {near .* syntax error}/}

do_catchsql_test 6.8 { 
  WITH x AS (SELECT * FROM t1) UPDATE t2 SET a = 10, b = ;







|







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
do_catchsql_test 6.5 {
  WITH x AS (SELECT * FROM t1)
  DELETE FROM t2 WHERE;
} {1 {near ";": syntax error}}

do_catchsql_test 6.6 { 
  WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHERE
} {1 {incomplete input}}

do_catchsql_test 6.7 { 
  WITH x AS (SELECT * FROM t1) DELETE FROM t2 WHRE 1;
} {/1 {near .* syntax error}/}

do_catchsql_test 6.8 { 
  WITH x AS (SELECT * FROM t1) UPDATE t2 SET a = 10, b = ;
Changes to test/zerodamage.test.
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
                    WHERE value BETWEEN 1 AND 400;
  }
  set ::max_journal_size 0
  db eval {
    UPDATE t1 SET y=randomblob(50) WHERE x=123;
  }
  concat [file_control_powersafe_overwrite db -1] [set ::max_journal_size]
} {0 1 2576}

# Repeat the previous step with zero-damage turned off.  This time the
# maximum rollback journal size should be much larger.
#
do_test zerodamage-2.1 {
  set ::max_journal_size 0
  db close
  sqlite3 db file:test.db?psow=FALSE -uri 1
  db eval {
    UPDATE t1 SET y=randomblob(50) WHERE x=124;
  }
  concat [file_control_powersafe_overwrite db -1] [set ::max_journal_size]
} {0 0 24704}

if {[wal_is_capable]} {
  # Run a WAL-mode transaction with POWERSAFE_OVERWRITE on to verify that the
  # WAL file does not get too big.
  #
  do_test zerodamage-3.0 {
    db eval {







|












|







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
                    WHERE value BETWEEN 1 AND 400;
  }
  set ::max_journal_size 0
  db eval {
    UPDATE t1 SET y=randomblob(50) WHERE x=123;
  }
  concat [file_control_powersafe_overwrite db -1] [set ::max_journal_size]
} [list 0 1 [expr ([atomic_batch_write test.db]==0)*2576]]

# Repeat the previous step with zero-damage turned off.  This time the
# maximum rollback journal size should be much larger.
#
do_test zerodamage-2.1 {
  set ::max_journal_size 0
  db close
  sqlite3 db file:test.db?psow=FALSE -uri 1
  db eval {
    UPDATE t1 SET y=randomblob(50) WHERE x=124;
  }
  concat [file_control_powersafe_overwrite db -1] [set ::max_journal_size]
} [list 0 0 [expr ([atomic_batch_write test.db]==0)*24704]]

if {[wal_is_capable]} {
  # Run a WAL-mode transaction with POWERSAFE_OVERWRITE on to verify that the
  # WAL file does not get too big.
  #
  do_test zerodamage-3.0 {
    db eval {
Added 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
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
255
256
# 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.
#
#***********************************************************************
#

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
}

forcedelete test.zip
do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip');
  PRAGMA table_info(zz);
} {
  0 name {} 1 {} 1 
  1 mode {} 0 {} 0 
  2 mtime {} 0 {} 0 
  3 sz {} 0 {} 0 
  4 rawdata {} 0 {} 0
  5 data {} 0 {} 0
  6 method {} 0 {} 0
}

do_catchsql_test 1.1.0.1 {
  INSERT INTO zz(name, mode, mtime, sz, rawdata, method) 
  VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
} {1 {constraint failed}}
do_catchsql_test 1.1.0.1 {
  INSERT INTO zz(name, mtime, sz, rawdata, method) 
  VALUES('g.txt', 1000000002, 5, '12345', 0);
} {1 {constraint failed}}

do_execsql_test 1.1.1 {
  INSERT INTO zz(name, mode, mtime, data, method) 
  VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0);
}
do_execsql_test 1.1.2 {
  INSERT INTO zz(name, mode, mtime, data, method) 
  VALUES('g.txt', NULL, 1000000002, '12345', 0);
}

do_execsql_test 1.2 {
  SELECT name, mtime, data FROM zipfile('test.zip')
} {
  f.txt 1000000000 abcde 
  g.txt 1000000002 12345
}

do_execsql_test 1.3 {
  INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt', 
    '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb'
  );
}

do_execsql_test 1.4 {
  SELECT name, mtime, data, method FROM zipfile('test.zip');
} {
  f.txt 1000000000 abcde 0
  g.txt 1000000002 12345 0
  h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
}

ifcapable json1 {
  do_execsql_test 1.4.1 {
    SELECT name, json_extract( zipfile_cds(z) , '$.crc32')!=0
    FROM zipfile('test.zip');
  } {
    f.txt 1
    g.txt 1
    h.txt 1
  }
}

do_execsql_test 1.5.1 {
  BEGIN;
    INSERT INTO zz(name, mode, mtime, data, method)
    VALUES('i.txt', '-rw-r--r--', 1000000006, 'zxcvb', 0);
    SELECT name FROM zz;
  COMMIT;
} {f.txt g.txt h.txt i.txt}
do_execsql_test 1.5.2 {
  SELECT name FROM zz;
} {f.txt g.txt h.txt i.txt}
do_execsql_test 1.5.3 {
  SELECT data FROM zz WHERE name='i.txt';
} {zxcvb}

do_execsql_test 1.6.0 {
  DELETE FROM zz WHERE name='g.txt';
  SELECT name FROM zz;
} {f.txt h.txt i.txt}

do_execsql_test 1.6.1 {
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  f.txt 33188 1000000000 abcde 0
  h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 1000000006 zxcvb 0
}

do_execsql_test 1.6.2 {
  UPDATE zz SET mtime=4 WHERE name='i.txt';
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  f.txt 33188 1000000000 abcde 0
  h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

do_execsql_test 1.6.3 {
  UPDATE zz SET mode='-rw-r--r-x' WHERE name='h.txt';
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  f.txt 33188 1000000000 abcde 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

do_execsql_test 1.6.4 {
  UPDATE zz SET name = 'blue.txt' WHERE name='f.txt';
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  blue.txt 33188 1000000000 abcde 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

do_execsql_test 1.6.5 {
  UPDATE zz SET data = 'edcba' WHERE name='blue.txt';
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  blue.txt 33188 1000000000 edcba 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

do_execsql_test 1.6.6 {
  UPDATE zz SET mode=NULL, data = NULL WHERE name='blue.txt';
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  blue.txt/ 16877 1000000000 {} 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

do_catchsql_test 1.6.7 {
  UPDATE zz SET data=NULL WHERE name='i.txt'
} {1 {constraint failed}}
do_execsql_test 1.6.8 {
  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
} {
  blue.txt/ 16877 1000000000 {} 0
  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
  i.txt 33188 4 zxcvb 0
}

#-------------------------------------------------------------------------
db close
forcedelete test.zip
reset_db
load_static_extension db zipfile
do_execsql_test 2.1 {
  CREATE VIRTUAL TABLE zzz USING zipfile('test.zip');
  INSERT INTO zzz(name, mode) VALUES('dirname', 'drwxr-xr-x');
  SELECT name, mode, data FROM zzz;
} {dirname/ 16877 {}}
do_execsql_test 2.2 {
  INSERT INTO zzz(name, data) VALUES('dirname2', NULL);
  INSERT INTO zzz(name, data) VALUES('dirname2/file1.txt', 'abcdefghijklmnop');
  SELECT name, mode, data FROM zzz;
} {
  dirname/ 16877 {}
  dirname2/ 16877 {}
  dirname2/file1.txt 33188 abcdefghijklmnop
}

do_catchsql_test 2.3 {
  UPDATE zzz SET name = 'dirname3' WHERE name = 'dirname/';
} {0 {}}
do_execsql_test 2.4 {
  SELECT name, mode, data FROM zzz;
} {
  dirname3/ 16877 {}
  dirname2/ 16877 {}
  dirname2/file1.txt 33188 abcdefghijklmnop
}

# If on unix, check that the [unzip] utility can unpack our archive.
#
if {$::tcl_platform(platform)=="unix"} {
  do_test 2.5.1 {
    forcedelete dirname
    forcedelete dirname2
    set rc [catch { exec unzip test.zip > /dev/null } msg]
    list $rc $msg
  } {0 {}}
  do_test 2.5.2 { file isdir dirname3 } 1
  do_test 2.5.3 { file isdir dirname2 } 1
  do_test 2.5.4 { file isdir dirname2/file1.txt } 0
  do_test 2.5.5 { 
    set fd [open dirname2/file1.txt]
    set data [read $fd]
    close $fd
    set data
  } {abcdefghijklmnop}
}

#-------------------------------------------------------------------------
reset_db
forcedelete test.zip
load_static_extension db zipfile

do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE temp.x1 USING zipfile('test.zip');
  INSERT INTO x1(name, data) VALUES('dir1/', NULL);
  INSERT INTO x1(name, data) VALUES('file1', '1234');
  INSERT INTO x1(name, data) VALUES('dir1/file2', '5678');
}
foreach {tn fname} {
  1 dir1
  2 file1
  3 dir1/file2
} {
  do_catchsql_test 3.1.$tn.0 {
    INSERT INTO x1(name, data) VALUES($fname, NULL);
  } {1 {constraint failed}}
  do_catchsql_test 3.1.$tn.1 {
    INSERT INTO x1(name, data) VALUES($fname || '/', NULL);
  } {1 {constraint failed}}
  do_catchsql_test 3.1.$tn.2 {
    INSERT INTO x1(name, data) VALUES($fname, 'abcd');
  } {1 {constraint failed}}
}

do_catchsql_test 3.2 {
  SELECT rowid FROM x1
} {1 {no such column: rowid}}


finish_test

Changes to tool/lempar.c.
702
703
704
705
706
707
708


709
710
711
712
713
714
715
  ParseTOKENTYPE yyLookaheadToken  /* Value of the lookahead token */
){
  int yygoto;                     /* The next state */
  int yyact;                      /* The next action */
  yyStackEntry *yymsp;            /* The top of the parser's stack */
  int yysize;                     /* Amount to pop the stack */
  ParseARG_FETCH;


  yymsp = yypParser->yytos;
#ifndef NDEBUG
  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    yysize = yyRuleInfo[yyruleno].nrhs;
    if( yysize ){
      fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
        yyTracePrompt,







>
>







702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
  ParseTOKENTYPE yyLookaheadToken  /* Value of the lookahead token */
){
  int yygoto;                     /* The next state */
  int yyact;                      /* The next action */
  yyStackEntry *yymsp;            /* The top of the parser's stack */
  int yysize;                     /* Amount to pop the stack */
  ParseARG_FETCH;
  (void)yyLookahead;
  (void)yyLookaheadToken;
  yymsp = yypParser->yytos;
#ifndef NDEBUG
  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    yysize = yyRuleInfo[yyruleno].nrhs;
    if( yysize ){
      fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
        yyTracePrompt,
Changes to tool/mkshellc.tcl.
26
27
28
29
30
31
32










33
34
35
36
37
38
39
40
41
42



43
44
45
46
47
48
49
** source file to help make the command-line program easier to compile.
**
** To modify this program, get a copy of the canonical SQLite source tree,
** edit the src/shell.c.in" and/or some of the other files that are included
** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
*/}
set in [open $topdir/src/shell.c.in rb]










while {1} {
  set lx [gets $in]
  if {[eof $in]} break;
  if {[regexp {^INCLUDE } $lx]} {
    set cfile [lindex $lx 1]
    puts $out "/************************* Begin $cfile ******************/"
    set in2 [open $topdir/src/$cfile rb]
    while {![eof $in2]} {
      set lx [gets $in2]
      if {[regexp {^#include "sqlite} $lx]} continue



      set lx [string map [list __declspec(dllexport) {}] $lx]
      puts $out $lx
    }
    close $in2
    puts $out "/************************* End $cfile ********************/"
    continue
  }







>
>
>
>
>
>
>
>
>
>

|






|

>
>
>







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
** source file to help make the command-line program easier to compile.
**
** To modify this program, get a copy of the canonical SQLite source tree,
** edit the src/shell.c.in" and/or some of the other files that are included
** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
*/}
set in [open $topdir/src/shell.c.in rb]
proc omit_redundant_typedefs {line} {
  global typedef_seen
  if {[regexp {^typedef .*;} $line]} {
    if {[info exists typedef_seen($line)]} {
      return "/* $line */"
    }
    set typedef_seen($line) 1
  }
  return $line
}
while {1} {
  set lx [omit_redundant_typedefs [gets $in]]
  if {[eof $in]} break;
  if {[regexp {^INCLUDE } $lx]} {
    set cfile [lindex $lx 1]
    puts $out "/************************* Begin $cfile ******************/"
    set in2 [open $topdir/src/$cfile rb]
    while {![eof $in2]} {
      set lx [omit_redundant_typedefs [gets $in2]]
      if {[regexp {^#include "sqlite} $lx]} continue
      if {[regexp {^# *include "test_windirent.h"} $lx]} {
        set lx "/* $lx */"
      }
      set lx [string map [list __declspec(dllexport) {}] $lx]
      puts $out $lx
    }
    close $in2
    puts $out "/************************* End $cfile ********************/"
    continue
  }
Added tool/sqltclsh.c.in.






































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
** This is the source code to a "tclsh" that has SQLite built-in.
**
** The startup script is located as follows:
**
**   (1)  Open the executable as an appended SQLite database and try to
**        read the startup script out of that database.
**
**   (2)  If the first argument is a readable file, try to open that file
**        as an SQLite database and read the startup script out of that
**        database.
**
**   (3)  If the first argument is a readable file with a ".tcl" extension,
**        then try to run that script directly.
**
** If none of the above steps work, then the program runs as an interactive
** tclsh.
*/
#define TCLSH_INIT_PROC sqlite3_tclapp_init_proc
#define SQLITE_ENABLE_DBSTAT_VTAB 1
#undef SQLITE_THREADSAFE
#define SQLITE_THREADSAFE 0
#undef SQLITE_ENABLE_COLUMN_METADATA
#define SQLITE_OMIT_DECLTYPE 1
#define SQLITE_OMIT_DEPRECATED 1
#define SQLITE_OMIT_PROGRESS_CALLBACK 1
#define SQLITE_OMIT_SHARED_CACHE 1
#define SQLITE_DEFAULT_MEMSTATUS 0
#define SQLITE_MAX_EXPR_DEPTH 0
INCLUDE sqlite3.c
INCLUDE $ROOT/ext/misc/appendvfs.c
#ifdef SQLITE_HAVE_ZLIB
INCLUDE $ROOT/ext/misc/zipfile.c
INCLUDE $ROOT/ext/misc/sqlar.c
#endif
INCLUDE $ROOT/src/tclsqlite.c

const char *sqlite3_tclapp_init_proc(Tcl_Interp *interp){
  (void)interp;
  sqlite3_appendvfs_init(0,0,0);
#ifdef SQLITE_HAVE_ZLIB
  sqlite3_auto_extension((void(*)(void))sqlite3_sqlar_init);
  sqlite3_auto_extension((void(*)(void))sqlite3_zipfile_init);
#endif

  return
BEGIN_STRING
INCLUDE $ROOT/tool/sqltclsh.tcl
END_STRING
;
}
Added tool/sqltclsh.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
# Try to open the executable as a database and read the "scripts.data"
# field where "scripts.name" is 'main.tcl'
#
catch {
  if {![file exists $argv0] && [file exists $argv0.exe]} {
    append argv0 .exe
  }
  sqlite3 db $argv0 -vfs apndvfs -create 0
  set mainscript [db one {
      SELECT sqlar_uncompress(data,sz) FROM sqlar WHERE name='main.tcl'
  }]
}
if {[info exists mainscript]} {
  eval $mainscript
  return
} else {
  catch {db close}
}

# Try to open file named in the first argument as a database and
# read the "scripts.data" field where "scripts.name" is 'main.tcl'
#
if {[llength $argv]>0 && [file readable [lindex $argv 0]]} {
  catch {
    sqlite3 db [lindex $argv 0] -vfs apndvfs -create 0
    set mainscript [db one {SELECT data FROM scripts WHERE name='main.tcl'}]
    set argv0 [lindex $argv 0]
    set argv [lrange $argv 1 end]
  }
  if {[info exists mainscript]} {
    eval $mainscript
    return
  } else {
    catch {db close}
  }
  if {[string match *.tcl [lindex $argv 0]]} {
    set fd [open [lindex $argv 0] rb]
    set mainscript [read $fd]
    close $fd
    unset fd
    set argv0 [lindex $argv 0]
    set argv [lrange $argv 1 end]
  }
  if {[info exists mainscript]} {
    eval $mainscript
    return
  }
}

# If all else fails, do an interactive loop
#
set line {}
while {![eof stdin]} {
  if {$line!=""} {
    puts -nonewline "> "
  } else {
    puts -nonewline "% "
  }
  flush stdout
  append line [gets stdin]
  if {[info complete $line]} {
    if {[catch {uplevel #0 $line} result]} {
      puts stderr "Error: $result"
    } elseif {$result!=""} {
      puts $result
    }
    set line {}
  } else {
    append line \\n"
  }
}