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: |
6ef3de810d54563c227045b16197b801 |
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
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 | $(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 \ | | > | 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 | # executables needed for testing # TESTPROGS = \ testfixture$(TEXE) \ sqlite3$(TEXE) \ sqlite3_analyzer$(TEXE) \ sqldiff$(TEXE) \ | | > | > | 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 | 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 \ | > | > > > > > | 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 | # <<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 | > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > | 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 | LDFLAGS = $(LDOPTS) !ENDIF # <<mark>> # Start with the Tcl related linker options. # !IF $(NO_TCL)==0 | | > > > > > > > | | 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 | # TESTPROGS = \ testfixture.exe \ $(SQLITE3EXE) \ sqlite3_analyzer.exe \ sqlite3_checker.exe \ sqldiff.exe \ | | > > | 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 | 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. # | | > > > > > > > > | 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 | 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) | | | 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 | 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 \ | > | > > > > > > > > > > > > | 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 | 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 | | | | 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 | .\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 \ | | > > > > > > > | | 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 | <h1 align="center">SQLite Source Repository</h1> This repository contains the complete source code for the SQLite database | | | 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 | 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. | < | | 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 | 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 | | | | | | 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 | * **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 | | | 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.23.0 |
Changes to autoconf/Makefile.am.
1 |
| | | 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 | # 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. # | > | > > > > > > > > | 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 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | | 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 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' | | | | 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 | # # 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 | | | 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 | --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 | | | 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 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | 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 | 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. | | | 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 | 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=" | | | 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 | 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="\\ | | | 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 | pScan->pOrder = pNew; n++; } } } } | | > > > > > | 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 | if( *pRc==SQLITE_OK ){ zAppend = sqlite3_vmprintf(zFmt, ap); if( zAppend ){ nAppend = STRLEN(zAppend); zRet = (char*)sqlite3_malloc(nIn + nAppend + 1); } if( zAppend && zRet ){ | | | 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 | 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; | | | 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 | return rc; } /* ** Create candidate indexes in database [dbm] based on the data in ** linked-list pScan. */ | | | 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 | 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 ){ | | | 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 | } 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); } | > > > | | 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 | 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; | | | 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 | 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 ){ | | | 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 | "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); | | | 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 | 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 { | | | | | 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 | 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 \ | | > | > | 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 | int pgsz = lsmFsPageSize(pDb->pFS); int nQuant = LSM_AUTOWORK_QUANT * pgsz; int nBefore; int nAfter; int nDiff; if( nQuant>pDb->nTreeLimit ){ | | | 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 | 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 ){ | < > < | | 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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** — 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 | ){ 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 ){ | > | | 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 | /* ** 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 | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < | > | > > > > > | > > > > > > > | > > > > > > > > > > > > > | | > | < > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < < | > > | | > > > > > | | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | > > > > > > > | 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(¤tTime); SystemTimeToFileTime(¤tTime, &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 | */ 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]; | > | > < | 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 | ** 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. */ | | > | 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 | if( eType==SQLITE_TEXT ){ z = sqlite3_value_text(pVal); }else{ z = sqlite3_value_blob(pVal); } if( memcmp(a, z, n) ) return 0; a += n; | < | 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 | } return SQLITE_OK; } /* ** This function queries the database for the names of the columns of table | | < < | < < | 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 | u8 *pAlloc = 0; char **azCol = 0; u8 *abPK = 0; assert( pazCol && pabPK ); nThis = sqlite3Strlen30(zThis); | > > > > > > > > > > > > > > > | > | 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 | int i; for(i=0; i<pTab->nCol; i++){ if( abPK[i] ){ pTab->abPK = abPK; break; } } | > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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; } } | < | 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 | 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; | > > > > > > > > > | | | | | | | | | | | | | | | | | > > > > | | | 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 | 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 */ | | | 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 | rc = sessionConflictHandler( SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 ); } }else{ assert( op==SQLITE_INSERT ); | > > > > > > > > > > > > | | | | > > | 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 | schemaMismatch = 1; sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): " "primary key mismatch for table %s", zTab ); } else{ sApply.nCol = nCol; | > > > > > > | | | | | | > > | 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> ** 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 | $(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 \ | > | | 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 | # TESTPROGS = \ testfixture$(EXE) \ sqlite3$(EXE) \ sqlite3_analyzer$(EXE) \ sqlite3_checker$(EXE) \ sqldiff$(EXE) \ | | > > | 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 | 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 \ | > > | > > | 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 | ** 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){ | > > | > | 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 | static void freePage(MemPage *pPage, int *pRC){ if( (*pRC)==SQLITE_OK ){ *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); } } /* | | | < | 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 | */ 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 | | | 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 | ** 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 */ | < | > | 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 | 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; | | | 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 | ** 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)); | | | 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 | if( p ){ int i; for(i=0; i<p->nExpr; i++){ heightOfExpr(p->a[i].pExpr, pnHeight); } } } | | | > < | 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 | 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; | < | 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 | ** Implementation of the length() function */ static void lengthFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ | < < > > | | | < > > | > | | 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 | 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 | < | | 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 | /* 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, | | > > > > | 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 | ** 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); | | | 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 | 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 ) { | | | 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 | 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 ); | > > > > > | | | | | | | | | > | < < | | 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 | ** 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 */ | < | 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 | ** 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) ){ | > > > | | < | < < | < | < | | | | | | | < | 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 | h = osCreateFile2((LPCWSTR)zConverted, dwDesiredAccess, dwShareMode, dwCreationDisposition, &extendedParameters); if( h!=INVALID_HANDLE_VALUE ) break; if( isReadWrite ){ | | > | > | > | > | > | > | 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 | assert( isOpen(pPager->fd) ); dc = sqlite3OsDeviceCharacteristics(pPager->fd); #else UNUSED_PARAMETER(pPager); #endif #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE | | | 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 | 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); | < > > | | 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 | // 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 */ | | | > > > | 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 | /* ** 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: | | > > > > > > < | | 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 | #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> | > > > > > | > > > > > > > > | 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 | 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 ){ | > | > | 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 | "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 ){ | > | | > > > > > > > > > > > | 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 | /* ** 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 */ | | | | | > > > > > > > > > > > > > > | 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 | #define SEP_Tab "\t" #define SEP_Space " " #define SEP_Comma "," #define SEP_CrLf "\r\n" #define SEP_Unit "\x1F" #define SEP_Record "\x1E" | < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | j--; } z[j++] = c; } while( j>0 && IsSpace(z[j-1]) ){ j--; } z[j] = 0; if( strlen30(z)>=79 ){ | | > > | > > | 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 | { "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++){ | | | 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 | " 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" | | > > | | 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 | 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(); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | 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 | } #elif HAVE_LINENOISE /* ** Linenoise completion callback */ static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){ | | | 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 | } } z[j] = c; } if( j<i ) z[j] = 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } /* ** 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". */ | | | | 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 | void *pX ){ FILE *f = (FILE*)pArg; UNUSED_PARAMETER(mType); UNUSED_PARAMETER(pP); if( f ){ const char *z = (const char*)pX; | | | 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 | ){ sqlite3_stmt *pQuery = 0; sqlite3_stmt *pInsert = 0; char *zQuery = 0; char *zInsert = 0; int rc; int i, j, n; | | | | 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 | sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); } sqlite3_close(newDb); } /* | | > > > > > > > > > > > > > > > > > > > > > > | 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 | "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++){ | | | 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 | */ 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; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | < | < < | | < | < | < | < < | < < < < < < < < < < < < < < < | < < < < < < | < > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | 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 | 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{ | | | 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 | 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); | | | | 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 | if( p->db==0 ){ /* As a fall-back open a TEMP database */ p->zDbFilename = 0; open_db(p, 0); } }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 | } sqlite3_close(pSrc); }else if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ if( nArg==2 ){ | | | 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 | 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 ){ | | | 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 | 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); | | | 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 | 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); | | | 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 | 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; } | | < | < | < | 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 | #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)) | < | 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 | 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 | | | | 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 | ** 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. | > < | 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 </b> ** <td>→ <td>Size of UTF-16 ** TEXT in bytes ** <tr><td><b>sqlite3_value_type</b><td>→<td>Default ** datatype of the value ** <tr><td><b>sqlite3_value_numeric_type </b> ** <td>→ <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 </b> ** <td>→ <td>Size of UTF-16 ** TEXT in bytes ** <tr><td><b>sqlite3_value_type</b><td>→<td>Default ** datatype of the value ** <tr><td><b>sqlite3_value_numeric_type </b> ** <td>→ <td>Best numeric datatype of the value ** <tr><td><b>sqlite3_value_nochange </b> ** <td>→ <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 | ** 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] | > > > > > > > > > > > > > > > > > > > | | 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 | /* Used to get the current process ID */ #if !defined(_WIN32) # include <unistd.h> # define GETPID getpid #elif !defined(_WIN32_WCE) # ifndef SQLITE_AMALGAMATION | > | > | 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 | ** ************************************************************************* ** 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) | < | 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 | ** 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. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # define BAD_INTPTR_T ((intptr_t)(-1)) #endif /* ** We need to provide the necessary structures and related types. */ | | > | < < > > > > > > | 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 | if( lastTokenParsed==TK_SEMI ){ tokenType = 0; }else if( lastTokenParsed==0 ){ break; }else{ tokenType = TK_SEMI; } | | | 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 | 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 */ | | > | 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 | /* ** 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 ){ | | | 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 | /* 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) ); | | > > > > > > > > > | > | 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 | 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 */ | < < | 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 | } 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) ); | < | > | < < < | > > > > > | 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 | (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; | > | > | > > | 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 | 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 ); | | > > > > > < | 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 | for(i=0; i<pCtx->argc; i++){ assert( memIsValid(pCtx->argv[i]) ); REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); } #endif pMem->n++; | < | | | | | | < < < < < | | | | > | > > > > > > > | 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 | VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE | | | | | > > > > > > | 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 | break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = 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 | #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); | | | | > | 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 | ** 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; | > > | | 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 | 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 */ | < | 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 | 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; | < < | 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 | 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){ | | < < < | 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 | 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; | < | < < | 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 | } 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 ){ | | > > > > > > | 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 | /* 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 | | | 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 | 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); | > > > > > > > > > > > > | | 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 | } } 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; | > > > > > > > > > > > > > > > > | | | > | | 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 | 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 | | | 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 | 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} | > | | | | > | 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 | 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; } | > > > | | > | 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 | # 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. # | | > > | 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 | 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 # | > | | | | | | | | | | > | 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 | #************************************************************************* # 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 | | | 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 | 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}} | > | | | > > > > | < > | 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 | # 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. # #************************************************************************* # | | | 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 | 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 { | | | | | | | | | | | | | | | | | | | | | 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 | } {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} | | | | 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 | # 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. # | | | 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 | 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. | | | 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 | 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. # | > > > | > > | 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 | 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. # | | > > | 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 | 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} } | | > > | 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 | 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/} | | | 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 | 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 | | | 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 | }} err] if {$rc && $err!="no such table: t1"} { error $err } } } | | | 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 | 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. # | > | | | | | | | | | > | 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 | 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 | > > > > > > > > > > > > | | > > > > | > > > > > > > > > > > > > > > > > > > | 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 | } } -test { faultsim_test_result {0 {}} set contents [db eval {SELECT * FROM t1}] if {$contents != "1 2"} { error "Bad database contents ($contents)" } | > | | | | | | > | 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 | }} 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 | | | 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 | } {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" | | | | 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 | 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\"" | | | 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 | 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" | | | 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 | 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)} { | | | 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 | openclose=[openclose_db], maxopen = 1 ) } } { execsql { DROP TABLE IF EXISTS s } | | | 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 | 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)} { | | | | | | | | > | 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 | } 0 do_test 2.$tn.2 { execsql { BEGIN; INSERT INTO t1 VALUES(1); } db2 file exists test.db-journal | | | 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 | INSERT INTO t1 SELECT NULL, randomblob(100) FROM s; } do_execsql_test 3.1 { VACUUM } db close tvfs delete | > | | | > | 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 | execsql { PRAGMA lock_status } } {main exclusive temp closed} do_test wal2-6.3.4 { execsql { BEGIN; INSERT INTO t1 VALUES('Groucho'); } | > > > | | > > > > | | > | 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 | 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. # | | | | 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 | execsql { PRAGMA page_size = 1024 } execsql { PRAGMA journal_mode = wal } } {wal} do_test walmode-1.2 { file size test.db } {1024} | > | | | | | | | | | > | 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 | # 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} | > | | | > > | | | > | 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 | 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} | < | > | | 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 | # 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". # | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | 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 | | | 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 | 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] | | | | 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 | ** 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} { | > > > > > > > > > > | | > > > | 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" } } |