Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge all changes through the first 3.9.0 beta from trunk. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | apple-osx |
Files: | files | file ages | folders |
SHA1: |
1ccae39b8a7094c2cee2f3fea57c847d |
User & Date: | drh 2015-10-09 17:28:56.474 |
Context
2015-10-13
| ||
17:49 | Merge 3.9.0 prerelease changes into the apple-osx branch. (check-in: 1900ce011c user: drh tags: apple-osx) | |
2015-10-09
| ||
17:28 | Merge all changes through the first 3.9.0 beta from trunk. (check-in: 1ccae39b8a user: drh tags: apple-osx) | |
14:37 | Add --enable-fts5 and --enable-json1 options to the amalgamation autoconf package. (check-in: 8a4e19888f user: dan tags: trunk) | |
2015-09-24
| ||
14:43 | Merge recent trunk enhancements into the apple-osx branch. (check-in: 4dd06d8ba1 user: drh tags: apple-osx) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
61 62 63 64 65 66 67 | # Should the database engine be compiled threadsafe # #TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@ # Any target libraries which libsqlite must be linked against # | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | # Should the database engine be compiled threadsafe # #TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@ # Any target libraries which libsqlite must be linked against # TLIBS = @LIBS@ $(LIBS) # Flags controlling use of the in memory btree implementation # # SQLITE_TEMP_STORE is 0 to force temporary tables to be in a file, 1 to # default to file, 2 to default to memory, and 3 to force temporary # tables to always be in memory. # |
︙ | ︙ | |||
171 172 173 174 175 176 177 | expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo \ fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ fts5.lo \ func.lo global.lo hash.lo \ | | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo \ fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ fts5.lo \ func.lo global.lo hash.lo \ icu.lo insert.lo journal.lo json1.lo legacy.lo loadext.lo \ main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \ memjournal.lo \ mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \ table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ |
︙ | ︙ | |||
268 269 270 271 272 273 274 | $(TOP)/src/status.c \ $(TOP)/src/shell.c \ $(TOP)/src/sqlite.h.in \ $(TOP)/src/sqlite3ext.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/table.c \ | | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | $(TOP)/src/status.c \ $(TOP)/src/shell.c \ $(TOP)/src/sqlite.h.in \ $(TOP)/src/sqlite3ext.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/table.c \ $(TOP)/src/tclsqlite.c \ $(TOP)/src/threads.c \ $(TOP)/src/tokenize.c \ $(TOP)/src/treeview.c \ $(TOP)/src/trigger.c \ $(TOP)/src/utf.c \ $(TOP)/src/update.c \ $(TOP)/src/util.c \ $(TOP)/src/vacuum.c \ |
︙ | ︙ | |||
345 346 347 348 349 350 351 352 353 354 355 356 357 358 | $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c SRC += \ $(TOP)/ext/sqlrr/sqlrr.h \ $(TOP)/ext/sqlrr/sqlrr.c \ $(TOP)/ext/rbu/sqlite3rbu.h \ $(TOP)/ext/rbu/sqlite3rbu.c # Generated source code files # SRC += \ keywordhash.h \ opcodes.c \ | > > > | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c SRC += \ $(TOP)/ext/sqlrr/sqlrr.h \ $(TOP)/ext/sqlrr/sqlrr.c \ $(TOP)/ext/rbu/sqlite3rbu.h \ $(TOP)/ext/rbu/sqlite3rbu.c SRC += \ $(TOP)/ext/misc/json1.c # Generated source code files # SRC += \ keywordhash.h \ opcodes.c \ |
︙ | ︙ | |||
415 416 417 418 419 420 421 | $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/misc/ieee754.c \ | < | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/wholenumber.c |
︙ | ︙ | |||
550 551 552 553 554 555 556 | # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db | < < < < < < > > > > > > | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.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 FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h libsqlite3.la sqlite3$(TEXE) $(HAVE_TCL:1=libtclsqlite3.la) Makefile: $(TOP)/Makefile.in |
︙ | ︙ | |||
581 582 583 584 585 586 587 | libtclsqlite3.la: tclsqlite.lo libsqlite3.la $(LTLINK) -no-undefined -o $@ tclsqlite.lo \ libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \ -rpath "$(TCLLIBDIR)/sqlite3" \ -version-info "8:6:8" | | | | | | | | | | 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 | libtclsqlite3.la: tclsqlite.lo libsqlite3.la $(LTLINK) -no-undefined -o $@ tclsqlite.lo \ libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \ -rpath "$(TCLLIBDIR)/sqlite3" \ -version-info "8:6:8" sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h $(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \ $(TOP)/src/shell.c libsqlite3.la \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZERSHELL_OPT) \ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) fuzzcheck$(TEXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS) mptester$(TEXE): sqlite3.c $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) -rpath "$(libdir)" MPTEST1=./mptester$(TEXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20 MPTEST2=./mptester$(TEXE) mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20 |
︙ | ︙ | |||
620 621 622 623 624 625 626 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # | | > > > > | 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 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # .target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c rm -rf tsrc mkdir tsrc cp -f $(SRC) tsrc rm tsrc/sqlite.h.in tsrc/parse.y $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c cp fts5.c fts5.h tsrc touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl cp tsrc/shell.c tsrc/sqlite3ext.h . sqlite3ext.h: .target_source cp tsrc/sqlite3ext.h . tclsqlite3.c: sqlite3.c echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c |
︙ | ︙ | |||
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c # FTS5 things # FTS5_SRC = \ $(TOP)/ext/fts5/fts5.h \ $(TOP)/ext/fts5/fts5Int.h \ $(TOP)/ext/fts5/fts5_aux.c \ $(TOP)/ext/fts5/fts5_buffer.c \ | > > > | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 | fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c json1.lo: $(TOP)/ext/misc/json1.c $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c # FTS5 things # FTS5_SRC = \ $(TOP)/ext/fts5/fts5.h \ $(TOP)/ext/fts5/fts5Int.h \ $(TOP)/ext/fts5/fts5_aux.c \ $(TOP)/ext/fts5/fts5_buffer.c \ |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
386 387 388 389 390 391 392 | !ENDIF !ENDIF # These are additional compiler options used for the shell executable. # !IFNDEF SHELL_COMPILE_OPTS !IF $(DYNAMIC_SHELL)!=0 | | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | !ENDIF !ENDIF # These are additional compiler options used for the shell executable. # !IFNDEF SHELL_COMPILE_OPTS !IF $(DYNAMIC_SHELL)!=0 SHELL_COMPILE_OPTS = -DSQLITE_SHELL_JSON1 $(SHELL_CCONV_OPTS) -DSQLITE_API=__declspec(dllimport) !ELSE SHELL_COMPILE_OPTS = -DSQLITE_SHELL_JSON1 $(SHELL_CCONV_OPTS) !ENDIF !ENDIF # This is the core library that the shell executable should depend on. # !IFNDEF SHELL_CORE_DEP !IF $(DYNAMIC_SHELL)!=0 |
︙ | ︙ | |||
1004 1005 1006 1007 1008 1009 1010 | $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c \ $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\icu\icu.c \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rtree\rtree.c \ $(TOP)\ext\rbu\sqlite3rbu.h \ | | > | 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 | $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c \ $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\icu\icu.c \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rtree\rtree.c \ $(TOP)\ext\rbu\sqlite3rbu.h \ $(TOP)\ext\rbu\sqlite3rbu.c \ $(TOP)\ext\misc\json1.c # Generated source code files # SRC5 = \ keywordhash.h \ opcodes.c \ |
︙ | ︙ | |||
1206 1207 1208 1209 1210 1211 1212 | # FUZZDATA = \ $(TOP)\test\fuzzdata1.db \ $(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata3.db \ $(TOP)\test\fuzzdata4.db | | | | | | | | | | | | | 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 | # FUZZDATA = \ $(TOP)\test\fuzzdata1.db \ $(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata3.db \ $(TOP)\test\fuzzdata4.db # Extra compiler options for various shell tools # SHELL_COMPILE_OPTS = -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: dll libsqlite3.lib sqlite3.exe libtclsqlite3.lib libsqlite3.lib: $(LIBOBJ) $(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS) libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) sqlite3.exe: $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h $(LTLINK) $(SHELL_COMPILE_OPTS) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c \ /link /pdb:sqlite3sh.pdb $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) sqldiff.exe: $(TOP)\tool\sqldiff.c sqlite3.c sqlite3.h $(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c sqlite3.c fuzzershell.exe: $(TOP)\tool\fuzzershell.c sqlite3.c sqlite3.h $(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) \ $(TOP)\tool\fuzzershell.c sqlite3.c fuzzcheck.exe: $(TOP)\test\fuzzcheck.c sqlite3.c sqlite3.h $(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(TOP)\test\fuzzcheck.c sqlite3.c mptester.exe: $(TOP)\mptest\mptest.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h $(LTLINK) $(NO_WARN) $(SHELL_COMPILE_OPTS) $(TOP)\mptest\mptest.c \ /link $(LTLINKOPTS) $(LTLIBPATHS) $(SHELL_LINK_OPTS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) MPTEST1 = mptester mptest.db $(TOP)\mptest\crash01.test --repeat 20 MPTEST2 = mptester mptest.db $(TOP)\mptest\multiwrite01.test --repeat 20 |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # | | > > | 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # .target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c -rmdir /Q/S tsrc 2>NUL -mkdir tsrc for %i in ($(SRC1)) do copy /Y %i tsrc for %i in ($(SRC2)) do copy /Y %i tsrc for %i in ($(SRC3)) do copy /Y %i tsrc for %i in ($(SRC4)) do copy /Y %i tsrc for %i in ($(SRC5)) do copy /Y %i tsrc copy /Y fts5.c tsrc copy /Y fts5.h tsrc del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source sqlite3.c: .target_source sqlite3ext.h $(TOP)\tool\mksqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl $(MKSQLITE3C_ARGS) |
︙ | ︙ |
Changes to VERSION.
|
| | | 1 | 3.9.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@ -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.c sqlite3.h |
︙ | ︙ |
Changes to autoconf/configure.ac.
︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 | else DYNAMIC_EXTENSION_FLAGS=-DSQLITE_OMIT_LOAD_EXTENSION=1 fi AC_MSG_CHECKING([for whether to support dynamic extensions]) AC_MSG_RESULT($enable_dynamic_extensions) AC_SUBST(DYNAMIC_EXTENSION_FLAGS) #----------------------------------------------------------------------- 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... # | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | else DYNAMIC_EXTENSION_FLAGS=-DSQLITE_OMIT_LOAD_EXTENSION=1 fi AC_MSG_CHECKING([for whether to support dynamic extensions]) AC_MSG_RESULT($enable_dynamic_extensions) AC_SUBST(DYNAMIC_EXTENSION_FLAGS) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-fts5 # AC_ARG_ENABLE(fts5, [AS_HELP_STRING( [--enable-fts5], [include fts5 support [default=no]])], [], [enable_fts5=no]) if test x"$enable_fts5" == "xyes"; then AC_SEARCH_LIBS(log, m) FTS5_FLAGS=-DSQLITE_ENABLE_FTS5 fi AC_SUBST(FTS5_FLAGS) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-json1 # AC_ARG_ENABLE(json1, [AS_HELP_STRING( [--enable-json1], [include json1 support [default=no]])], [], [enable_json1=no]) if test x"$enable_json1" == "xyes"; then JSON1_FLAGS=-DSQLITE_ENABLE_JSON1 fi AC_SUBST(JSON1_FLAGS) #----------------------------------------------------------------------- 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... # |
︙ | ︙ |
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.9.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.9.0' PACKAGE_STRING='sqlite 3.9.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H |
︙ | ︙ | |||
898 899 900 901 902 903 904 905 906 907 908 909 910 911 | with_tcl enable_readline with_readline_lib with_readline_inc enable_debug enable_amalgamation enable_load_extension enable_gcov ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS | > > > > > | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | with_tcl enable_readline with_readline_lib with_readline_inc enable_debug enable_amalgamation enable_load_extension enable_fts3 enable_fts4 enable_fts5 enable_json1 enable_rtree enable_gcov ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS |
︙ | ︙ | |||
1450 1451 1452 1453 1454 1455 1456 | # # 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 | | | 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 | # # 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.9.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. |
︙ | ︙ | |||
1515 1516 1517 1518 1519 1520 1521 | --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 | | | 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 | --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.9.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] |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 | --disable-tcl do not build TCL extension --disable-readline disable readline support [default=detect] --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately --disable-load-extension Disable loading of external extensions --enable-gcov Enable coverage testing using gcov Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] | > > > > > | 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 | --disable-tcl do not build TCL extension --disable-readline disable readline support [default=detect] --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately --disable-load-extension Disable loading of external extensions --enable-fts3 Enable the FTS3 extension --enable-fts4 Enable the FTS4 extension --enable-fts5 Enable the FTS5 extension --enable-json1 Enable the JSON1 extension --enable-rtree Enable the RTREE extension --enable-gcov Enable coverage testing using gcov Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] |
︙ | ︙ | |||
1630 1631 1632 1633 1634 1635 1636 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 | 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.9.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 |
︙ | ︙ | |||
2049 2050 2051 2052 2053 2054 2055 | 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. | | | 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 | 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.9.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
3907 3908 3909 3910 3911 3912 3913 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext | | | | | 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:3924: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:3927: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:3930: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 |
︙ | ︙ | |||
5119 5120 5121 5122 5123 5124 5125 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. | | | 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 5136 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in |
︙ | ︙ | |||
6644 6645 6646 6647 6648 6649 6650 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6661: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6665: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes |
︙ | ︙ | |||
6983 6984 6985 6986 6987 6988 6989 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7000: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7004: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes |
︙ | ︙ | |||
7088 7089 7090 7091 7092 7093 7094 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7105: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7109: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
7143 7144 7145 7146 7147 7148 7149 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7160: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7164: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
9523 9524 9525 9526 9527 9528 9529 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 9540 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
9619 9620 9621 9622 9623 9624 9625 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 9636 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ######### # See whether we should enable Full Text Search extensions # Check whether --enable-fts3 was given. if test "${enable_fts3+set}" = set; then : enableval=$enable_fts3; enable_fts3=yes else enable_fts3=no fi if test "${enable_fts3}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3" fi # Check whether --enable-fts4 was given. if test "${enable_fts4+set}" = set; then : enableval=$enable_fts4; enable_fts4=yes else enable_fts4=no fi if test "${enable_fts4}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 $as_echo_n "checking for library containing log... " >&6; } if ${ac_cv_search_log+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char log (); int main () { return log (); ; return 0; } _ACEOF for ac_lib in '' m; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_log=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_log+:} false; then : break fi done if ${ac_cv_search_log+:} false; then : else ac_cv_search_log=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5 $as_echo "$ac_cv_search_log" >&6; } ac_res=$ac_cv_search_log if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi # Check whether --enable-fts5 was given. if test "${enable_fts5+set}" = set; then : enableval=$enable_fts5; enable_fts5=yes else enable_fts5=no fi if test "${enable_fts5}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 $as_echo_n "checking for library containing log... " >&6; } if ${ac_cv_search_log+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char log (); int main () { return log (); ; return 0; } _ACEOF for ac_lib in '' m; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_log=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_log+:} false; then : break fi done if ${ac_cv_search_log+:} false; then : else ac_cv_search_log=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5 $as_echo "$ac_cv_search_log" >&6; } ac_res=$ac_cv_search_log if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi ######### # See whether we should enable JSON1 # Check whether --enable-json1 was given. if test "${enable_json1+set}" = set; then : enableval=$enable_json1; enable_json1=yes else enable_json1=no fi if test "${enable_json1}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1" fi ######### # See whether we should enable RTREE # Check whether --enable-rtree was given. if test "${enable_rtree+set}" = set; then : enableval=$enable_rtree; enable_rtree=yes else enable_rtree=no fi if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; |
︙ | ︙ | |||
11804 11805 11806 11807 11808 11809 11810 | 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=" | | | 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 | 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.9.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 $@ |
︙ | ︙ | |||
11870 11871 11872 11873 11874 11875 11876 | 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="\\ | | | 12051 12052 12053 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 | 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.9.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 configure.ac.
︙ | ︙ | |||
555 556 557 558 559 560 561 562 563 564 565 566 567 568 | [use_loadextension=$enableval],[use_loadextension=yes]) if test "${use_loadextension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | [use_loadextension=$enableval],[use_loadextension=yes]) if test "${use_loadextension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ######### # See whether we should enable Full Text Search extensions AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], [Enable the FTS3 extension]), [enable_fts3=yes],[enable_fts3=no]) if test "${enable_fts3}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3" fi AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4], [Enable the FTS4 extension]), [enable_fts4=yes],[enable_fts4=no]) if test "${enable_fts4}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4" AC_SEARCH_LIBS([log],[m]) fi AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5], [Enable the FTS5 extension]), [enable_fts5=yes],[enable_fts5=no]) if test "${enable_fts5}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5" AC_SEARCH_LIBS([log],[m]) fi ######### # See whether we should enable JSON1 AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1], [Enable the JSON1 extension]), [enable_json1=yes],[enable_json1=no]) if test "${enable_json1}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1" fi ######### # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension]), [enable_rtree=yes],[enable_rtree=no]) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; |
︙ | ︙ |
Changes to ext/fts3/fts3.c.
︙ | ︙ | |||
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 | static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ #if SQLITE_VERSION_NUMBER>=3008002 if( sqlite3_libversion_number()>=3008002 ){ pIdxInfo->estimatedRows = nRow; } #endif } /* ** Implementation of the xBestIndex method for FTS3 tables. There ** are three possible strategies, in order of preference: ** ** 1. Direct lookup by rowid or docid. ** 2. Full-text search using a MATCH operator on a non-docid column. | > > > > > > > > > > > > > | 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 | static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ #if SQLITE_VERSION_NUMBER>=3008002 if( sqlite3_libversion_number()>=3008002 ){ pIdxInfo->estimatedRows = nRow; } #endif } /* ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this ** extension is currently being used by a version of SQLite too old to ** support index-info flags. In that case this function is a no-op. */ static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){ #if SQLITE_VERSION_NUMBER>=3008012 if( sqlite3_libversion_number()>=3008012 ){ pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; } #endif } /* ** Implementation of the xBestIndex method for FTS3 tables. There ** are three possible strategies, in order of preference: ** ** 1. Direct lookup by rowid or docid. ** 2. Full-text search using a MATCH operator on a non-docid column. |
︙ | ︙ | |||
1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 | case SQLITE_INDEX_CONSTRAINT_LE: case SQLITE_INDEX_CONSTRAINT_LT: iDocidLe = i; break; } } } iIdx = 1; if( iCons>=0 ){ pInfo->aConstraintUsage[iCons].argvIndex = iIdx++; pInfo->aConstraintUsage[iCons].omit = 1; } if( iLangidCons>=0 ){ | > > > | 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 | case SQLITE_INDEX_CONSTRAINT_LE: case SQLITE_INDEX_CONSTRAINT_LT: iDocidLe = i; break; } } } /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */ if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo); iIdx = 1; if( iCons>=0 ){ pInfo->aConstraintUsage[iCons].argvIndex = iIdx++; pInfo->aConstraintUsage[iCons].omit = 1; } if( iLangidCons>=0 ){ |
︙ | ︙ |
Changes to ext/fts3/fts3Int.h.
︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 | int nPrefix; /* Prefix length (0 for main terms index) */ Fts3Hash hPending; /* Pending terms table for this index */ } *aIndex; int nMaxPendingData; /* Max pending data before flush to disk */ int nPendingData; /* Current bytes of pending data */ sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ int iPrevLangid; /* Langid of recently inserted document */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) /* State variables used for validating that the transaction control ** methods of the virtual table are called at appropriate times. These ** values do not contribute to FTS functionality; they are used for ** verifying the operation of the SQLite core. */ | > | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | int nPrefix; /* Prefix length (0 for main terms index) */ Fts3Hash hPending; /* Pending terms table for this index */ } *aIndex; int nMaxPendingData; /* Max pending data before flush to disk */ int nPendingData; /* Current bytes of pending data */ sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ int iPrevLangid; /* Langid of recently inserted document */ int bPrevDelete; /* True if last operation was a delete */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) /* State variables used for validating that the transaction control ** methods of the virtual table are called at appropriate times. These ** values do not contribute to FTS functionality; they are used for ** verifying the operation of the SQLite core. */ |
︙ | ︙ |
Changes to ext/fts3/fts3_expr.c.
︙ | ︙ | |||
789 790 791 792 793 794 795 | Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */ int eType = pRoot->eType; /* Type of node in this tree */ if( nMaxDepth==0 ){ rc = SQLITE_ERROR; } | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | > > > | > > > > > > > > > > > > > > > > > > > > > > | 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 | Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */ int eType = pRoot->eType; /* Type of node in this tree */ if( nMaxDepth==0 ){ rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ Fts3Expr **apLeaf; apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth); if( 0==apLeaf ){ rc = SQLITE_NOMEM; }else{ memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); } if( rc==SQLITE_OK ){ int i; Fts3Expr *p; /* Set $p to point to the left-most leaf in the tree of eType nodes. */ for(p=pRoot; p->eType==eType; p=p->pLeft){ assert( p->pParent==0 || p->pParent->pLeft==p ); assert( p->pLeft && p->pRight ); } /* This loop runs once for each leaf in the tree of eType nodes. */ while( 1 ){ int iLvl; Fts3Expr *pParent = p->pParent; /* Current parent of p */ assert( pParent==0 || pParent->pLeft==p ); p->pParent = 0; if( pParent ){ pParent->pLeft = 0; }else{ pRoot = 0; } rc = fts3ExprBalance(&p, nMaxDepth-1); if( rc!=SQLITE_OK ) break; for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){ if( apLeaf[iLvl]==0 ){ apLeaf[iLvl] = p; p = 0; }else{ assert( pFree ); pFree->pLeft = apLeaf[iLvl]; pFree->pRight = p; pFree->pLeft->pParent = pFree; pFree->pRight->pParent = pFree; p = pFree; pFree = pFree->pParent; p->pParent = 0; apLeaf[iLvl] = 0; } } if( p ){ sqlite3Fts3ExprFree(p); rc = SQLITE_TOOBIG; break; } /* If that was the last leaf node, break out of the loop */ if( pParent==0 ) break; /* Set $p to point to the next leaf in the tree of eType nodes */ for(p=pParent->pRight; p->eType==eType; p=p->pLeft); /* Remove pParent from the original tree. */ assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); pParent->pRight->pParent = pParent->pParent; if( pParent->pParent ){ pParent->pParent->pLeft = pParent->pRight; }else{ assert( pParent==pRoot ); pRoot = pParent->pRight; } /* Link pParent into the free node list. It will be used as an ** internal node of the new tree. */ pParent->pParent = pFree; pFree = pParent; } if( rc==SQLITE_OK ){ p = 0; for(i=0; i<nMaxDepth; i++){ if( apLeaf[i] ){ if( p==0 ){ p = apLeaf[i]; p->pParent = 0; }else{ assert( pFree!=0 ); pFree->pRight = p; pFree->pLeft = apLeaf[i]; pFree->pLeft->pParent = pFree; pFree->pRight->pParent = pFree; p = pFree; pFree = pFree->pParent; p->pParent = 0; } } } pRoot = p; }else{ /* An error occurred. Delete the contents of the apLeaf[] array ** and pFree list. Everything else is cleaned up by the call to ** sqlite3Fts3ExprFree(pRoot) below. */ Fts3Expr *pDel; for(i=0; i<nMaxDepth; i++){ sqlite3Fts3ExprFree(apLeaf[i]); } while( (pDel=pFree)!=0 ){ pFree = pDel->pParent; sqlite3_free(pDel); } } assert( pFree==0 ); sqlite3_free( apLeaf ); } }else if( eType==FTSQUERY_NOT ){ Fts3Expr *pLeft = pRoot->pLeft; Fts3Expr *pRight = pRoot->pRight; pRoot->pLeft = 0; pRoot->pRight = 0; pLeft->pParent = 0; pRight->pParent = 0; rc = fts3ExprBalance(&pLeft, nMaxDepth-1); if( rc==SQLITE_OK ){ rc = fts3ExprBalance(&pRight, nMaxDepth-1); } if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRight); sqlite3Fts3ExprFree(pLeft); }else{ assert( pLeft && pRight ); pRoot->pLeft = pLeft; pLeft->pParent = pRoot; pRoot->pRight = pRight; pRight->pParent = pRoot; } } } if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRoot); pRoot = 0; } *pp = pRoot; return rc; } |
︙ | ︙ |
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | /* ** Calling this function indicates that subsequent calls to ** fts3PendingTermsAdd() are to add term/position-list pairs for the ** contents of the document with docid iDocid. */ static int fts3PendingTermsDocid( Fts3Table *p, /* Full-text table handle */ int iLangid, /* Language id of row being written */ sqlite_int64 iDocid /* Docid of row being written */ ){ assert( iLangid>=0 ); /* TODO(shess) Explore whether partially flushing the buffer on ** forced-flush would provide better performance. I suspect that if ** we ordered the doclists by size and flushed the largest until the ** buffer was half empty, that would let the less frequent terms ** generate longer doclists. */ | > > | > > | 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 | /* ** Calling this function indicates that subsequent calls to ** fts3PendingTermsAdd() are to add term/position-list pairs for the ** contents of the document with docid iDocid. */ static int fts3PendingTermsDocid( Fts3Table *p, /* Full-text table handle */ int bDelete, /* True if this op is a delete */ int iLangid, /* Language id of row being written */ sqlite_int64 iDocid /* Docid of row being written */ ){ assert( iLangid>=0 ); assert( bDelete==1 || bDelete==0 ); /* TODO(shess) Explore whether partially flushing the buffer on ** forced-flush would provide better performance. I suspect that if ** we ordered the doclists by size and flushed the largest until the ** buffer was half empty, that would let the less frequent terms ** generate longer doclists. */ if( iDocid<p->iPrevDocid || (iDocid==p->iPrevDocid && p->bPrevDelete==0) || p->iPrevLangid!=iLangid || p->nPendingData>p->nMaxPendingData ){ int rc = sqlite3Fts3PendingTermsFlush(p); if( rc!=SQLITE_OK ) return rc; } p->iPrevDocid = iDocid; p->iPrevLangid = iLangid; p->bPrevDelete = bDelete; return SQLITE_OK; } /* ** Discard the contents of the pending-terms hash tables. */ void sqlite3Fts3PendingTermsClear(Fts3Table *p){ |
︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 | assert( *pbFound==0 ); if( *pRC ) return; rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pSelect) ){ int i; int iLangid = langidFromSelect(p, pSelect); | > | | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 | assert( *pbFound==0 ); if( *pRC ) return; rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pSelect) ){ int i; int iLangid = langidFromSelect(p, pSelect); i64 iDocid = sqlite3_column_int64(pSelect, 0); rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid); for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){ int iCol = i-1; if( p->abNotindexed[iCol]==0 ){ const char *zText = (const char *)sqlite3_column_text(pSelect, i); rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[iCol]); aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i); } |
︙ | ︙ | |||
1313 1314 1315 1316 1317 1318 1319 | pNext = &pReader->aDoclist[pReader->nDoclist]; } if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){ if( fts3SegReaderIsPending(pReader) ){ Fts3HashElem *pElem = *(pReader->ppNextElem); | | | | > > > > > | | | 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 | pNext = &pReader->aDoclist[pReader->nDoclist]; } if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){ if( fts3SegReaderIsPending(pReader) ){ Fts3HashElem *pElem = *(pReader->ppNextElem); sqlite3_free(pReader->aNode); pReader->aNode = 0; if( pElem ){ char *aCopy; PendingList *pList = (PendingList *)fts3HashData(pElem); int nCopy = pList->nData+1; pReader->zTerm = (char *)fts3HashKey(pElem); pReader->nTerm = fts3HashKeysize(pElem); aCopy = (char*)sqlite3_malloc(nCopy); if( !aCopy ) return SQLITE_NOMEM; memcpy(aCopy, pList->aData, nCopy); pReader->nNode = pReader->nDoclist = nCopy; pReader->aNode = pReader->aDoclist = aCopy; pReader->ppNextElem++; assert( pReader->aNode ); } return SQLITE_OK; } fts3SegReaderSetEof(pReader); |
︙ | ︙ | |||
1560 1561 1562 1563 1564 1565 1566 | } /* ** Free all allocations associated with the iterator passed as the ** second argument. */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ | > | | > < > | 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 | } /* ** Free all allocations associated with the iterator passed as the ** second argument. */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ if( pReader ){ if( !fts3SegReaderIsPending(pReader) ){ sqlite3_free(pReader->zTerm); } if( !fts3SegReaderIsRootOnly(pReader) ){ sqlite3_free(pReader->aNode); } sqlite3_blob_close(pReader->pBlob); } sqlite3_free(pReader); } /* ** Allocate a new SegReader object. */ |
︙ | ︙ | |||
3508 3509 3510 3511 3512 3513 3514 | aSzDel = &aSzIns[p->nColumn+1]; } } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ int iCol; int iLangid = langidFromSelect(p, pStmt); | | | 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 | aSzDel = &aSzIns[p->nColumn+1]; } } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ int iCol; int iLangid = langidFromSelect(p, pStmt); rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0)); memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){ if( p->abNotindexed[iCol]==0 ){ const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); } |
︙ | ︙ | |||
5613 5614 5615 5616 5617 5618 5619 | if( bInsertDone==0 ){ rc = fts3InsertData(p, apVal, pRowid); if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ rc = FTS_CORRUPT_VTAB; } } if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ | | | 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 | if( bInsertDone==0 ){ rc = fts3InsertData(p, apVal, pRowid); if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ rc = FTS_CORRUPT_VTAB; } } if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid); } if( rc==SQLITE_OK ){ assert( p->iPrevDocid==*pRowid ); rc = fts3InsertTerms(p, iLangid, apVal, aSzIns); } if( p->bHasDocsize ){ fts3InsertDocsize(&rc, p, aSzIns); |
︙ | ︙ |
Changes to ext/fts5/fts5Int.h.
︙ | ︙ | |||
77 78 79 80 81 82 83 84 85 86 87 88 89 90 | extern int sqlite3_fts5_may_be_corrupt; # define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x)) #else # define assert_nc(x) assert(x) #endif typedef struct Fts5Global Fts5Global; /************************************************************************** ** Interface to code in fts5_config.c. fts5_config.c contains contains code ** to parse the arguments passed to the CREATE VIRTUAL TABLE statement. */ typedef struct Fts5Config Fts5Config; | > > > > > > > > > > > > > > | 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 | extern int sqlite3_fts5_may_be_corrupt; # define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x)) #else # define assert_nc(x) assert(x) #endif typedef struct Fts5Global Fts5Global; typedef struct Fts5Colset Fts5Colset; /* If a NEAR() clump or phrase may only match a specific set of columns, ** then an object of the following type is used to record the set of columns. ** Each entry in the aiCol[] array is a column that may be matched. ** ** This object is used by fts5_expr.c and fts5_index.c. */ struct Fts5Colset { int nCol; int aiCol[1]; }; /************************************************************************** ** Interface to code in fts5_config.c. fts5_config.c contains contains code ** to parse the arguments passed to the CREATE VIRTUAL TABLE statement. */ typedef struct Fts5Config Fts5Config; |
︙ | ︙ | |||
301 302 303 304 305 306 307 | ** Create/destroy an Fts5Index object. */ int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); int sqlite3Fts5IndexClose(Fts5Index *p); /* ** for( | | > | | 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 | ** Create/destroy an Fts5Index object. */ int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); int sqlite3Fts5IndexClose(Fts5Index *p); /* ** for( ** sqlite3Fts5IndexQuery(p, "token", 5, 0, 0, &pIter); ** 0==sqlite3Fts5IterEof(pIter); ** sqlite3Fts5IterNext(pIter) ** ){ ** i64 iRowid = sqlite3Fts5IterRowid(pIter); ** } */ /* ** Open a new iterator to iterate though all rowids that match the ** specified token or token prefix. */ int sqlite3Fts5IndexQuery( Fts5Index *p, /* FTS index to query */ const char *pToken, int nToken, /* Token (or prefix) to query for */ int flags, /* Mask of FTS5INDEX_QUERY_X flags */ Fts5Colset *pColset, /* Match these columns only */ Fts5IndexIter **ppIter /* OUT: New iterator object */ ); /* ** The various operations on open token or token prefix iterators opened ** using sqlite3Fts5IndexQuery(). */ int sqlite3Fts5IterEof(Fts5IndexIter*); |
︙ | ︙ | |||
366 367 368 369 370 371 372 373 374 375 376 377 378 379 | /* ** Indicate that subsequent calls to sqlite3Fts5IndexWrite() pertain to ** document iDocid. */ int sqlite3Fts5IndexBeginWrite( Fts5Index *p, /* Index to write to */ i64 iDocid /* Docid to add or remove data from */ ); /* ** Flush any data stored in the in-memory hash tables to the database. ** If the bCommit flag is true, also close any open blob handles. */ | > | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | /* ** Indicate that subsequent calls to sqlite3Fts5IndexWrite() pertain to ** document iDocid. */ int sqlite3Fts5IndexBeginWrite( Fts5Index *p, /* Index to write to */ int bDelete, /* True if current operation is a delete */ i64 iDocid /* Docid to add or remove data from */ ); /* ** Flush any data stored in the in-memory hash tables to the database. ** If the bCommit flag is true, also close any open blob handles. */ |
︙ | ︙ | |||
429 430 431 432 433 434 435 436 437 438 439 440 441 442 | int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v); int sqlite3Fts5GetVarintLen(u32 iVal); u8 sqlite3Fts5GetVarint(const unsigned char*, u64*); int sqlite3Fts5PutVarint(unsigned char *p, u64 v); #define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b) #define fts5GetVarint sqlite3Fts5GetVarint /* ** End of interface to code in fts5_varint.c. **************************************************************************/ /************************************************************************** | > > > > > > > > > | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v); int sqlite3Fts5GetVarintLen(u32 iVal); u8 sqlite3Fts5GetVarint(const unsigned char*, u64*); int sqlite3Fts5PutVarint(unsigned char *p, u64 v); #define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b) #define fts5GetVarint sqlite3Fts5GetVarint #define fts5FastGetVarint32(a, iOff, nVal) { \ nVal = (a)[iOff++]; \ if( nVal & 0x80 ){ \ iOff--; \ iOff += fts5GetVarint32(&(a)[iOff], nVal); \ } \ } /* ** End of interface to code in fts5_varint.c. **************************************************************************/ /************************************************************************** |
︙ | ︙ | |||
522 523 524 525 526 527 528 | int sqlite3Fts5StorageClose(Fts5Storage *p); int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); int sqlite3Fts5DropAll(Fts5Config*); int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); int sqlite3Fts5StorageDelete(Fts5Storage *p, i64); | | > | 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | int sqlite3Fts5StorageClose(Fts5Storage *p); int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); int sqlite3Fts5DropAll(Fts5Config*); int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); int sqlite3Fts5StorageDelete(Fts5Storage *p, i64); int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); int sqlite3Fts5StorageIntegrity(Fts5Storage *p); int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**); void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*); int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol); |
︙ | ︙ | |||
561 562 563 564 565 566 567 | */ typedef struct Fts5Expr Fts5Expr; typedef struct Fts5ExprNode Fts5ExprNode; typedef struct Fts5Parse Fts5Parse; typedef struct Fts5Token Fts5Token; typedef struct Fts5ExprPhrase Fts5ExprPhrase; typedef struct Fts5ExprNearset Fts5ExprNearset; | < | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 | */ typedef struct Fts5Expr Fts5Expr; typedef struct Fts5ExprNode Fts5ExprNode; typedef struct Fts5Parse Fts5Parse; typedef struct Fts5Token Fts5Token; typedef struct Fts5ExprPhrase Fts5ExprPhrase; typedef struct Fts5ExprNearset Fts5ExprNearset; struct Fts5Token { const char *p; /* Token text (not NULL terminated) */ int n; /* Size of buffer p in bytes */ }; /* Parse a MATCH expression. */ |
︙ | ︙ | |||
629 630 631 632 633 634 635 | Fts5ExprNearset *sqlite3Fts5ParseNearset( Fts5Parse*, Fts5ExprNearset*, Fts5ExprPhrase* ); | | | | | 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 | Fts5ExprNearset *sqlite3Fts5ParseNearset( Fts5Parse*, Fts5ExprNearset*, Fts5ExprPhrase* ); Fts5Colset *sqlite3Fts5ParseColset( Fts5Parse*, Fts5Colset*, Fts5Token * ); void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*); void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); /* ** End of interface to code in fts5_expr.c. **************************************************************************/ |
︙ | ︙ |
Changes to ext/fts5/fts5_aux.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ****************************************************************************** */ #include "fts5Int.h" | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ****************************************************************************** */ #include "fts5Int.h" #include <math.h> /* amalgamator: keep */ /* ** Object used to iterate through all "coalesced phrase instances" in ** a single column of the current row. If the phrase instances in the ** column being considered do not overlap, this object simply iterates ** through them. Or, if they do overlap (share one or more tokens in ** common), each set of overlapping instances is treated as a single |
︙ | ︙ |
Changes to ext/fts5/fts5_buffer.c.
︙ | ︙ | |||
181 182 183 184 185 186 187 | if( i>=n ){ /* EOF */ *piOff = -1; return 1; }else{ i64 iOff = *piOff; int iVal; | | | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | if( i>=n ){ /* EOF */ *piOff = -1; return 1; }else{ i64 iOff = *piOff; int iVal; fts5FastGetVarint32(a, i, iVal); if( iVal==1 ){ fts5FastGetVarint32(a, i, iVal); iOff = ((i64)iVal) << 32; fts5FastGetVarint32(a, i, iVal); } *piOff = iOff + (iVal-2); *pi = i; return 0; } } |
︙ | ︙ | |||
229 230 231 232 233 234 235 | int sqlite3Fts5PoslistWriterAppend( Fts5Buffer *pBuf, Fts5PoslistWriter *pWriter, i64 iPos ){ static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; int rc = SQLITE_OK; | > | | | | | | | > | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | int sqlite3Fts5PoslistWriterAppend( Fts5Buffer *pBuf, Fts5PoslistWriter *pWriter, i64 iPos ){ static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; int rc = SQLITE_OK; if( 0==sqlite3Fts5BufferGrow(&rc, pBuf, 5+5+5) ){ if( (iPos & colmask) != (pWriter->iPrev & colmask) ){ pBuf->p[pBuf->n++] = 1; pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); pWriter->iPrev = (iPos & colmask); } pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2); pWriter->iPrev = iPos; } return rc; } void *sqlite3Fts5MallocZero(int *pRc, int nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc(nByte); |
︙ | ︙ | |||
286 287 288 289 290 291 292 293 294 295 296 | ** Return true if character 't' may be part of an FTS5 bareword, or false ** otherwise. Characters that may be part of barewords: ** ** * All non-ASCII characters, ** * The 52 upper and lower case ASCII characters, and ** * The 10 integer ASCII characters. ** * The underscore character "_" (0x5F). */ int sqlite3Fts5IsBareword(char t){ u8 aBareword[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 .. 0x0F */ | > | | 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 | ** Return true if character 't' may be part of an FTS5 bareword, or false ** otherwise. Characters that may be part of barewords: ** ** * All non-ASCII characters, ** * The 52 upper and lower case ASCII characters, and ** * The 10 integer ASCII characters. ** * The underscore character "_" (0x5F). ** * The unicode "subsitute" character (0x1A). */ int sqlite3Fts5IsBareword(char t){ u8 aBareword[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 .. 0x0F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 0x10 .. 0x1F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 .. 0x2F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30 .. 0x3F */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 .. 0x4F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50 .. 0x5F */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 .. 0x6F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70 .. 0x7F */ }; return (t & 0x80) || aBareword[(int)t]; } |
Changes to ext/fts5/fts5_expr.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /* ** Functions generated by lemon from fts5parse.y. */ void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64)); void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*)); void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); struct Fts5Expr { Fts5Index *pIndex; Fts5ExprNode *pRoot; int bDesc; /* Iterate in descending rowid order */ int nPhrase; /* Number of phrases in expression */ Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ | > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | /* ** Functions generated by lemon from fts5parse.y. */ void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64)); void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*)); void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); #ifndef NDEBUG #include <stdio.h> void sqlite3Fts5ParserTrace(FILE*, char*); #endif struct Fts5Expr { Fts5Index *pIndex; Fts5ExprNode *pRoot; int bDesc; /* Iterate in descending rowid order */ int nPhrase; /* Number of phrases in expression */ Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ |
︙ | ︙ | |||
85 86 87 88 89 90 91 | struct Fts5ExprPhrase { Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ Fts5Buffer poslist; /* Current position list */ int nTerm; /* Number of entries in aTerm[] */ Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */ }; | < < < < < < < < < < | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | struct Fts5ExprPhrase { Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ Fts5Buffer poslist; /* Current position list */ int nTerm; /* Number of entries in aTerm[] */ Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */ }; /* ** One or more phrases that must appear within a certain token distance of ** each other within each matching document. */ struct Fts5ExprNearset { int nNear; /* NEAR parameter */ Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */ int nPhrase; /* Number of entries in aPhrase[] array */ Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */ }; /* ** Parse context. |
︙ | ︙ | |||
272 273 274 275 276 277 278 | if( p ){ sqlite3Fts5ParseNodeFree(p->pRoot); sqlite3_free(p->apExprPhrase); sqlite3_free(p); } } | | | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | if( p ){ sqlite3Fts5ParseNodeFree(p->pRoot); sqlite3_free(p->apExprPhrase); sqlite3_free(p); } } static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){ int i; for(i=0; i<pColset->nCol; i++){ if( pColset->aiCol[i]==iCol ) return 1; } return 0; } |
︙ | ︙ | |||
401 402 403 404 405 406 407 | ** ** SQLITE_OK is returned if an error occurs, or an SQLite error code ** otherwise. It is not considered an error code if the current rowid is ** not a match. */ static int fts5ExprPhraseIsMatch( Fts5ExprNode *pNode, /* Node pPhrase belongs to */ | | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | ** ** SQLITE_OK is returned if an error occurs, or an SQLite error code ** otherwise. It is not considered an error code if the current rowid is ** not a match. */ static int fts5ExprPhraseIsMatch( Fts5ExprNode *pNode, /* Node pPhrase belongs to */ Fts5Colset *pColset, /* Restrict matches to these columns */ Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */ int *pbMatch /* OUT: Set to true if really a match */ ){ Fts5PoslistWriter writer = {0}; Fts5PoslistReader aStatic[4]; Fts5PoslistReader *aIter = aStatic; int i; |
︙ | ︙ | |||
801 802 803 804 805 806 807 | while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){ prev = *p++; } return p - (*pa); } static int fts5ExprExtractColset ( | | | 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 | while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){ prev = *p++; } return p - (*pa); } static int fts5ExprExtractColset ( Fts5Colset *pColset, /* Colset to filter on */ const u8 *pPos, int nPos, /* Position list */ Fts5Buffer *pBuf /* Output buffer */ ){ int rc = SQLITE_OK; int i; fts5BufferZero(pBuf); |
︙ | ︙ | |||
864 865 866 867 868 869 870 | ** of a single term only, grab pointers into the poslist managed by the ** fts5_index.c iterator object. This is much faster than synthesizing ** a new poslist the way we have to for more complicated phrase or NEAR ** expressions. */ Fts5ExprNearset *pNear = pNode->pNear; Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; | | | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | ** of a single term only, grab pointers into the poslist managed by the ** fts5_index.c iterator object. This is much faster than synthesizing ** a new poslist the way we have to for more complicated phrase or NEAR ** expressions. */ Fts5ExprNearset *pNear = pNode->pNear; Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; Fts5Colset *pColset = pNear->pColset; const u8 *pPos; int nPos; int rc; assert( pNode->eType==FTS5_TERM ); assert( pNear->nPhrase==1 && pPhrase->nTerm==1 ); assert( pPhrase->aTerm[0].pSynonym==0 ); |
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | sqlite3Fts5IterClose(p->pIter); p->pIter = 0; } rc = sqlite3Fts5IndexQuery( pExpr->pIndex, p->zTerm, strlen(p->zTerm), (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), &p->pIter ); assert( rc==SQLITE_OK || p->pIter==0 ); if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){ bEof = 0; } } | > | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | sqlite3Fts5IterClose(p->pIter); p->pIter = 0; } rc = sqlite3Fts5IndexQuery( pExpr->pIndex, p->zTerm, strlen(p->zTerm), (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), pNear->pColset, &p->pIter ); assert( rc==SQLITE_OK || p->pIter==0 ); if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){ bEof = 0; } } |
︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 | nNear = FTS5_DEFAULT_NEARDIST; } pNear->nNear = nNear; } /* ** The second argument passed to this function may be NULL, or it may be | | | | | | | 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 | nNear = FTS5_DEFAULT_NEARDIST; } pNear->nNear = nNear; } /* ** The second argument passed to this function may be NULL, or it may be ** an existing Fts5Colset object. This function returns a pointer to ** a new colset object containing the contents of (p) with new value column ** number iCol appended. ** ** If an OOM error occurs, store an error code in pParse and return NULL. ** The old colset object (if any) is not freed in this case. */ static Fts5Colset *fts5ParseColset( Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ Fts5Colset *p, /* Existing colset object */ int iCol /* New column to add to colset object */ ){ int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */ Fts5Colset *pNew; /* New colset object to return */ assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iCol<pParse->pConfig->nCol ); pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol); if( pNew==0 ){ pParse->rc = SQLITE_NOMEM; }else{ int *aiCol = pNew->aiCol; int i, j; for(i=0; i<nCol; i++){ if( aiCol[i]==iCol ) return pNew; |
︙ | ︙ | |||
1793 1794 1795 1796 1797 1798 1799 | for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); #endif } return pNew; } | | | | | 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 | for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); #endif } return pNew; } Fts5Colset *sqlite3Fts5ParseColset( Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ Fts5Colset *pColset, /* Existing colset object */ Fts5Token *p ){ Fts5Colset *pRet = 0; int iCol; char *z; /* Dequoted copy of token p */ z = sqlite3Fts5Strndup(&pParse->rc, p->p, p->n); if( pParse->rc==SQLITE_OK ){ Fts5Config *pConfig = pParse->pConfig; sqlite3Fts5Dequote(z); |
︙ | ︙ | |||
1828 1829 1830 1831 1832 1833 1834 | return pRet; } void sqlite3Fts5ParseSetColset( Fts5Parse *pParse, Fts5ExprNearset *pNear, | | | 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 | return pRet; } void sqlite3Fts5ParseSetColset( Fts5Parse *pParse, Fts5ExprNearset *pNear, Fts5Colset *pColset ){ if( pNear ){ pNear->pColset = pColset; }else{ sqlite3_free(pColset); } } |
︙ | ︙ | |||
2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 | int rc = SQLITE_OK; void *pCtx = (void*)pGlobal; for(i=0; rc==SQLITE_OK && i<(sizeof(aFunc) / sizeof(aFunc[0])); i++){ struct Fts5ExprFunc *p = &aFunc[i]; rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); } return rc; } /* ** Return the number of phrases in expression pExpr. */ | > > > > > | 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 | int rc = SQLITE_OK; void *pCtx = (void*)pGlobal; for(i=0; rc==SQLITE_OK && i<(sizeof(aFunc) / sizeof(aFunc[0])); i++){ struct Fts5ExprFunc *p = &aFunc[i]; rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); } /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */ #ifndef NDEBUG (void)sqlite3Fts5ParserTrace; #endif return rc; } /* ** Return the number of phrases in expression pExpr. */ |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
287 288 289 290 291 292 293 | ** Variables related to the accumulation of tokens and doclists within the ** in-memory hash tables before they are flushed to disk. */ Fts5Hash *pHash; /* Hash table for in-memory data */ int nMaxPendingData; /* Max pending data before flush to disk */ int nPendingData; /* Current bytes of pending data */ i64 iWriteRowid; /* Rowid for current doc being written */ | | | < < > | 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 | ** Variables related to the accumulation of tokens and doclists within the ** in-memory hash tables before they are flushed to disk. */ Fts5Hash *pHash; /* Hash table for in-memory data */ int nMaxPendingData; /* Max pending data before flush to disk */ int nPendingData; /* Current bytes of pending data */ i64 iWriteRowid; /* Rowid for current doc being written */ int bDelete; /* Current write is a delete */ /* Error state. */ int rc; /* Current error code */ /* State used by the fts5DataXXX() functions. */ sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */ sqlite3_stmt *pIdxSelect; int nRead; /* Total number of blocks read */ }; struct Fts5DoclistIter { u8 *aEof; /* Pointer to 1 byte past end of doclist */ /* Output variables. aPoslist==0 at EOF */ i64 iRowid; u8 *aPoslist; int nPoslist; int nSize; }; /* ** The contents of the "structure" record for each index are represented ** using an Fts5Structure record in memory. Which uses instances of the ** other Fts5StructureXXX types as components. */ |
︙ | ︙ | |||
1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 | }else{ pIter->pLeaf->p = (u8*)pList; pIter->pLeaf->nn = nList; pIter->pLeaf->szLeaf = nList; pIter->iEndofDoclist = nList+1; sqlite3Fts5BufferSet(&p->rc, &pIter->term, strlen(zTerm), (u8*)zTerm); pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); } }else{ iOff = 0; /* Next entry is not on the current page */ while( iOff==0 ){ fts5SegIterNextPage(p, pIter); pLeaf = pIter->pLeaf; | > | 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 | }else{ pIter->pLeaf->p = (u8*)pList; pIter->pLeaf->nn = nList; pIter->pLeaf->szLeaf = nList; pIter->iEndofDoclist = nList+1; sqlite3Fts5BufferSet(&p->rc, &pIter->term, strlen(zTerm), (u8*)zTerm); pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); if( pbNewTerm ) *pbNewTerm = 1; } }else{ iOff = 0; /* Next entry is not on the current page */ while( iOff==0 ){ fts5SegIterNextPage(p, pIter); pLeaf = pIter->pLeaf; |
︙ | ︙ | |||
1936 1937 1938 1939 1940 1941 1942 | ){ return; } pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno); } | < < < < < < < < | 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 | ){ return; } pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno); } #define fts5IndexSkipVarint(a, iOff) { \ int iEnd = iOff+9; \ while( (a[iOff++] & 0x80) && iOff<iEnd ); \ } /* ** The iterator object passed as the second argument currently contains |
︙ | ︙ | |||
1990 1991 1992 1993 1994 1995 1996 | iPgidx = szLeaf; iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); iOff = iTermOff; while( 1 ){ /* Figure out how many new bytes are in this term */ | | | 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 | iPgidx = szLeaf; iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); iOff = iTermOff; while( 1 ){ /* Figure out how many new bytes are in this term */ fts5FastGetVarint32(a, iOff, nNew); if( nKeep<nMatch ){ goto search_failed; } assert( nKeep>=nMatch ); if( nKeep==nMatch ){ int nCmp; |
︙ | ︙ | |||
2026 2027 2028 2029 2030 2031 2032 | } iPgidx += fts5GetVarint32(&a[iPgidx], nKeep); iTermOff += nKeep; iOff = iTermOff; /* Read the nKeep field of the next term. */ | | | 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 | } iPgidx += fts5GetVarint32(&a[iPgidx], nKeep); iTermOff += nKeep; iOff = iTermOff; /* Read the nKeep field of the next term. */ fts5FastGetVarint32(a, iOff, nKeep); } search_failed: if( bGe==0 ){ fts5DataRelease(pIter->pLeaf); pIter->pLeaf = 0; return; |
︙ | ︙ | |||
3701 3702 3703 3704 3705 3706 3707 | if( (ret + i) > nMax ) break; ret += i; } } return ret; } | | | | | > > > > > | 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 | if( (ret + i) > nMax ) break; ret += i; } } return ret; } #define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) { \ assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) ); \ memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob); \ (pBuf)->n += nBlob; \ } #define fts5BufferSafeAppendVarint(pBuf, iVal) { \ (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal)); \ assert( (pBuf)->nSpace>=(pBuf)->n ); \ } /* ** Flush the contents of in-memory hash table iHash to a new level-0 ** segment on disk. Also update the corresponding structure record. ** ** If an error occurs, set the Fts5Index.rc error code. If an error has |
︙ | ︙ | |||
3934 3935 3936 3937 3938 3939 3940 | fts5StructureRelease(pStruct); return fts5IndexReturn(p); } static void fts5PoslistCallback( Fts5Index *p, | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | | > > > < | > | > | | | > > > > > > > > > > > > > > > > | | | > > > | > | | < < | | > | < | | | > > > > | | | > > > > < | | < | | > | > > > > | 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 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 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 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 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 | fts5StructureRelease(pStruct); return fts5IndexReturn(p); } static void fts5PoslistCallback( Fts5Index *p, void *pContext, const u8 *pChunk, int nChunk ){ assert_nc( nChunk>=0 ); if( nChunk>0 ){ fts5BufferAppendBlob(&p->rc, (Fts5Buffer*)pContext, nChunk, pChunk); } } typedef struct PoslistCallbackCtx PoslistCallbackCtx; struct PoslistCallbackCtx { Fts5Buffer *pBuf; /* Append to this buffer */ Fts5Colset *pColset; /* Restrict matches to this column */ int eState; /* See above */ }; /* ** TODO: Make this more efficient! */ static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){ int i; for(i=0; i<pColset->nCol; i++){ if( pColset->aiCol[i]==iCol ) return 1; } return 0; } static void fts5PoslistFilterCallback( Fts5Index *p, void *pContext, const u8 *pChunk, int nChunk ){ PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext; assert_nc( nChunk>=0 ); if( nChunk>0 ){ /* Search through to find the first varint with value 1. This is the ** start of the next columns hits. */ int i = 0; int iStart = 0; if( pCtx->eState==2 ){ int iCol; fts5FastGetVarint32(pChunk, i, iCol); if( fts5IndexColsetTest(pCtx->pColset, iCol) ){ pCtx->eState = 1; fts5BufferAppendVarint(&p->rc, pCtx->pBuf, 1); }else{ pCtx->eState = 0; } } do { while( i<nChunk && pChunk[i]!=0x01 ){ while( pChunk[i] & 0x80 ) i++; i++; } if( pCtx->eState ){ fts5BufferAppendBlob(&p->rc, pCtx->pBuf, i-iStart, &pChunk[iStart]); } if( i<nChunk ){ int iCol; iStart = i; i++; if( i>=nChunk ){ pCtx->eState = 2; }else{ fts5FastGetVarint32(pChunk, i, iCol); pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol); if( pCtx->eState ){ fts5BufferAppendBlob(&p->rc, pCtx->pBuf, i-iStart, &pChunk[iStart]); iStart = i; } } } }while( i<nChunk ); } } /* ** Iterator pIter currently points to a valid entry (not EOF). This ** function appends the position list data for the current entry to ** buffer pBuf. It does not make a copy of the position-list size ** field. */ static void fts5SegiterPoslist( Fts5Index *p, Fts5SegIter *pSeg, Fts5Colset *pColset, Fts5Buffer *pBuf ){ if( pColset==0 ){ fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); }else{ PoslistCallbackCtx sCtx; sCtx.pBuf = pBuf; sCtx.pColset = pColset; sCtx.eState = pColset ? fts5IndexColsetTest(pColset, 0) : 1; assert( sCtx.eState==0 || sCtx.eState==1 ); fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback); } } /* ** Iterator pMulti currently points to a valid entry (not EOF). This ** function appends a copy of the position-list of the entry pMulti ** currently points to to buffer pBuf. ** ** If an error occurs, an error code is left in p->rc. It is assumed ** no error has already occurred when this function is called. */ static int fts5MultiIterPoslist( Fts5Index *p, Fts5IndexIter *pMulti, Fts5Colset *pColset, Fts5Buffer *pBuf ){ if( p->rc==SQLITE_OK ){ int iSz; int iData; Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ]; assert( fts5MultiIterEof(p, pMulti)==0 ); /* WRITEPOSLISTSIZE */ iSz = pBuf->n; fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2); iData = pBuf->n; fts5SegiterPoslist(p, pSeg, pColset, pBuf); if( pColset ){ int nActual = pBuf->n - iData; if( nActual!=pSeg->nPos ){ /* WRITEPOSLISTSIZE */ if( nActual==0 ){ return 1; }else{ int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2)); while( iSz<(iData-nReq) ){ pBuf->p[iSz++] = 0x80; } sqlite3Fts5PutVarint(&pBuf->p[iSz], nActual*2); } } } } return 0; } static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist; assert( pIter->aPoslist ); if( p>=pIter->aEof ){ pIter->aPoslist = 0; }else{ i64 iDelta; p += fts5GetVarint(p, (u64*)&iDelta); pIter->iRowid += iDelta; /* Read position list size */ if( p[0] & 0x80 ){ int nPos; pIter->nSize = fts5GetVarint32(p, nPos); pIter->nPoslist = (nPos>>1); }else{ pIter->nPoslist = ((int)(p[0])) >> 1; pIter->nSize = 1; } pIter->aPoslist = p; } } static void fts5DoclistIterInit( Fts5Buffer *pBuf, Fts5DoclistIter *pIter ){ memset(pIter, 0, sizeof(*pIter)); pIter->aPoslist = pBuf->p; pIter->aEof = &pBuf->p[pBuf->n]; fts5DoclistIterNext(pIter); } #if 0 /* ** Append a doclist to buffer pBuf. ** ** This function assumes that space within the buffer has already been ** allocated. */ static void fts5MergeAppendDocid( Fts5Buffer *pBuf, /* Buffer to write to */ i64 *piLastRowid, /* IN/OUT: Previous rowid written (if any) */ i64 iRowid /* Rowid to append */ ){ assert( pBuf->n!=0 || (*piLastRowid)==0 ); fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid); *piLastRowid = iRowid; } #endif #define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \ assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \ fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \ (iLastRowid) = (iRowid); \ } /* ** Buffers p1 and p2 contain doclists. This function merges the content ** of the two doclists together and sets buffer p1 to the result before ** returning. ** ** If an error occurs, an error code is left in p->rc. If an error has |
︙ | ︙ | |||
4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 | Fts5DoclistIter i1; Fts5DoclistIter i2; Fts5Buffer out; Fts5Buffer tmp; memset(&out, 0, sizeof(out)); memset(&tmp, 0, sizeof(tmp)); fts5DoclistIterInit(p1, &i1); fts5DoclistIterInit(p2, &i2); while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){ if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowid<i2.iRowid) ){ /* Copy entry from i1 */ | > | < < | | < < | | > > > | | > | | > > | | | | | | | > | > | | | 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 | Fts5DoclistIter i1; Fts5DoclistIter i2; Fts5Buffer out; Fts5Buffer tmp; memset(&out, 0, sizeof(out)); memset(&tmp, 0, sizeof(tmp)); sqlite3Fts5BufferGrow(&p->rc, &out, p1->n + p2->n); fts5DoclistIterInit(p1, &i1); fts5DoclistIterInit(p2, &i2); while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){ if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowid<i2.iRowid) ){ /* Copy entry from i1 */ fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid); fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize); fts5DoclistIterNext(&i1); } else if( i1.aPoslist==0 || i2.iRowid!=i1.iRowid ){ /* Copy entry from i2 */ fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize); fts5DoclistIterNext(&i2); } else{ i64 iPos1 = 0; i64 iPos2 = 0; int iOff1 = 0; int iOff2 = 0; u8 *a1 = &i1.aPoslist[i1.nSize]; u8 *a2 = &i2.aPoslist[i2.nSize]; Fts5PoslistWriter writer; memset(&writer, 0, sizeof(writer)); /* Merge the two position lists. */ fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferZero(&tmp); sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); while( p->rc==SQLITE_OK && (iPos1>=0 || iPos2>=0) ){ i64 iNew; if( iPos2<0 || (iPos1>=0 && iPos1<iPos2) ){ iNew = iPos1; sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); }else{ iNew = iPos2; sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); if( iPos1==iPos2 ){ sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1); } } p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew); } /* WRITEPOSLISTSIZE */ fts5BufferSafeAppendVarint(&out, tmp.n * 2); fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); fts5DoclistIterNext(&i1); fts5DoclistIterNext(&i2); } } fts5BufferSet(&p->rc, p1, out.n, out.p); fts5BufferFree(&tmp); |
︙ | ︙ | |||
4121 4122 4123 4124 4125 4126 4127 | } static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ int bDesc, /* True for "ORDER BY rowid DESC" */ const u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ | > | | 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 | } static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ int bDesc, /* True for "ORDER BY rowid DESC" */ const u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ Fts5Colset *pColset, /* Restrict matches to these columns */ Fts5IndexIter **ppIter /* OUT: New iterator */ ){ Fts5Structure *pStruct; Fts5Buffer *aBuf; const int nBuf = 32; aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); pStruct = fts5StructureRead(p); |
︙ | ︙ | |||
4160 4161 4162 4163 4164 4165 4166 4167 4168 | fts5BufferSwap(&doclist, &aBuf[i]); fts5BufferZero(&doclist); }else{ fts5MergePrefixLists(p, &doclist, &aBuf[i]); fts5BufferZero(&aBuf[i]); } } } | > | > > > | > > > > > > | > | 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 | fts5BufferSwap(&doclist, &aBuf[i]); fts5BufferZero(&doclist); }else{ fts5MergePrefixLists(p, &doclist, &aBuf[i]); fts5BufferZero(&aBuf[i]); } } iLastRowid = 0; } if( 0==sqlite3Fts5BufferGrow(&p->rc, &doclist, 9) ){ int iSave = doclist.n; assert( doclist.n!=0 || iLastRowid==0 ); fts5BufferSafeAppendVarint(&doclist, iRowid - iLastRowid); if( fts5MultiIterPoslist(p, p1, pColset, &doclist) ){ doclist.n = iSave; }else{ iLastRowid = iRowid; } } } for(i=0; i<nBuf; i++){ if( p->rc==SQLITE_OK ){ fts5MergePrefixLists(p, &doclist, &aBuf[i]); } fts5BufferFree(&aBuf[i]); } fts5MultiIterFree(p, p1); pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n); if( pData ){ pData->p = (u8*)&pData[1]; |
︙ | ︙ | |||
4191 4192 4193 4194 4195 4196 4197 | } /* ** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain ** to the document with rowid iRowid. */ | | > > | > > > | 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 | } /* ** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain ** to the document with rowid iRowid. */ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ assert( p->rc==SQLITE_OK ); /* Allocate the hash table if it has not already been allocated */ if( p->pHash==0 ){ p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData); } /* Flush the hash table to disk if required */ if( iRowid<p->iWriteRowid || (iRowid==p->iWriteRowid && p->bDelete==0) || (p->nPendingData > p->nMaxPendingData) ){ fts5IndexFlush(p); } p->iWriteRowid = iRowid; p->bDelete = bDelete; return fts5IndexReturn(p); } /* ** Commit data to disk. */ int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){ |
︙ | ︙ | |||
4302 4303 4304 4305 4306 4307 4308 | assert( p->pReader==0 ); sqlite3_finalize(p->pWriter); sqlite3_finalize(p->pDeleter); sqlite3_finalize(p->pIdxWriter); sqlite3_finalize(p->pIdxDeleter); sqlite3_finalize(p->pIdxSelect); sqlite3Fts5HashFree(p->pHash); | < | 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 | assert( p->pReader==0 ); sqlite3_finalize(p->pWriter); sqlite3_finalize(p->pDeleter); sqlite3_finalize(p->pIdxWriter); sqlite3_finalize(p->pIdxDeleter); sqlite3_finalize(p->pIdxSelect); sqlite3Fts5HashFree(p->pHash); sqlite3_free(p->zDataTbl); sqlite3_free(p); } return rc; } /* |
︙ | ︙ | |||
4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 | const char *pToken, int nToken /* Token to add or remove to or from index */ ){ int i; /* Used to iterate through indexes */ int rc = SQLITE_OK; /* Return code */ Fts5Config *pConfig = p->pConfig; assert( p->rc==SQLITE_OK ); /* Add the entry to the main terms index. */ rc = sqlite3Fts5HashWrite( p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken ); for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){ | > | 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 | const char *pToken, int nToken /* Token to add or remove to or from index */ ){ int i; /* Used to iterate through indexes */ int rc = SQLITE_OK; /* Return code */ Fts5Config *pConfig = p->pConfig; assert( p->rc==SQLITE_OK ); assert( (iCol<0)==p->bDelete ); /* Add the entry to the main terms index. */ rc = sqlite3Fts5HashWrite( p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken ); for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){ |
︙ | ︙ | |||
4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 | ** Open a new iterator to iterate though all rowid that match the ** specified token or token prefix. */ int sqlite3Fts5IndexQuery( Fts5Index *p, /* FTS index to query */ const char *pToken, int nToken, /* Token (or prefix) to query for */ int flags, /* Mask of FTS5INDEX_QUERY_X flags */ Fts5IndexIter **ppIter /* OUT: New iterator object */ ){ Fts5Config *pConfig = p->pConfig; Fts5IndexIter *pRet = 0; int iIdx = 0; Fts5Buffer buf = {0, 0, 0}; | > | 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 | ** Open a new iterator to iterate though all rowid that match the ** specified token or token prefix. */ int sqlite3Fts5IndexQuery( Fts5Index *p, /* FTS index to query */ const char *pToken, int nToken, /* Token (or prefix) to query for */ int flags, /* Mask of FTS5INDEX_QUERY_X flags */ Fts5Colset *pColset, /* Match these columns only */ Fts5IndexIter **ppIter /* OUT: New iterator object */ ){ Fts5Config *pConfig = p->pConfig; Fts5IndexIter *pRet = 0; int iIdx = 0; Fts5Buffer buf = {0, 0, 0}; |
︙ | ︙ | |||
4432 4433 4434 4435 4436 4437 4438 | if( pStruct ){ fts5MultiIterNew(p, pStruct, 1, flags, buf.p, nToken+1, -1, 0, &pRet); fts5StructureRelease(pStruct); } }else{ int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; buf.p[0] = FTS5_MAIN_PREFIX; | | | 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 | if( pStruct ){ fts5MultiIterNew(p, pStruct, 1, flags, buf.p, nToken+1, -1, 0, &pRet); fts5StructureRelease(pStruct); } }else{ int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; buf.p[0] = FTS5_MAIN_PREFIX; fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet); } if( p->rc ){ sqlite3Fts5IterClose(pRet); pRet = 0; fts5CloseReader(p); } |
︙ | ︙ | |||
4534 4535 4536 4537 4538 4539 4540 | assert( pIter->pIndex->rc==SQLITE_OK ); *piRowid = pSeg->iRowid; *pn = pSeg->nPos; if( pSeg->iLeafOffset+pSeg->nPos <= pSeg->pLeaf->szLeaf ){ *pp = &pSeg->pLeaf->p[pSeg->iLeafOffset]; }else{ fts5BufferZero(&pIter->poslist); | | | | | 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 | assert( pIter->pIndex->rc==SQLITE_OK ); *piRowid = pSeg->iRowid; *pn = pSeg->nPos; if( pSeg->iLeafOffset+pSeg->nPos <= pSeg->pLeaf->szLeaf ){ *pp = &pSeg->pLeaf->p[pSeg->iLeafOffset]; }else{ fts5BufferZero(&pIter->poslist); fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); *pp = pIter->poslist.p; } return fts5IndexReturn(pIter->pIndex); } /* ** This function is similar to sqlite3Fts5IterPoslist(), except that it ** copies the position list into the buffer supplied as the second ** argument. */ int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf){ Fts5Index *p = pIter->pIndex; Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; assert( p->rc==SQLITE_OK ); fts5BufferZero(pBuf); fts5SegiterPoslist(p, pSeg, 0, pBuf); return fts5IndexReturn(p); } /* ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). */ void sqlite3Fts5IterClose(Fts5IndexIter *pIter){ |
︙ | ︙ | |||
4725 4726 4727 4728 4729 4730 4731 | const char *z, /* Index key to query for */ int n, /* Size of index key in bytes */ int flags, /* Flags for Fts5IndexQuery */ u64 *pCksum /* IN/OUT: Checksum value */ ){ u64 cksum = *pCksum; Fts5IndexIter *pIdxIter = 0; | | | 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 | const char *z, /* Index key to query for */ int n, /* Size of index key in bytes */ int flags, /* Flags for Fts5IndexQuery */ u64 *pCksum /* IN/OUT: Checksum value */ ){ u64 cksum = *pCksum; Fts5IndexIter *pIdxIter = 0; int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter); while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){ i64 dummy; const u8 *pPos; int nPos; i64 rowid = sqlite3Fts5IterRowid(pIdxIter); rc = sqlite3Fts5IterPoslist(pIdxIter, &pPos, &nPos, &dummy); |
︙ | ︙ | |||
5099 5100 5101 5102 5103 5104 5105 | i64 iRowid = fts5MultiIterRowid(pIter); char *z = (char*)fts5MultiIterTerm(pIter, &n); /* If this is a new term, query for it. Update cksum3 with the results. */ fts5TestTerm(p, &term, z, n, cksum2, &cksum3); poslist.n = 0; | | | 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 | i64 iRowid = fts5MultiIterRowid(pIter); char *z = (char*)fts5MultiIterTerm(pIter, &n); /* If this is a new term, query for it. Update cksum3 with the results. */ fts5TestTerm(p, &term, z, n, cksum2, &cksum3); poslist.n = 0; fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist); while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ int iCol = FTS5_POS2COLUMN(iPos); int iTokOff = FTS5_POS2OFFSET(iPos); cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); } } fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); |
︙ | ︙ | |||
5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 | *pRc = rc; return; } fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } /* ** Buffer (a/n) is assumed to contain a list of serialized varints. Read ** each varint and append its string representation to buffer pBuf. Return ** after either the input buffer is exhausted or a 0 value is read. ** ** The return value is the number of bytes read from the input buffer. | > > > > > > > > > > > > > > > > > > > > > > > | 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 5398 5399 5400 5401 5402 5403 5404 5405 5406 | *pRc = rc; return; } fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } /* ** This is part of the fts5_decode() debugging aid. ** ** Arguments pBlob/nBlob contain an "averages" record. This function ** appends a human-readable representation of record to the buffer passed ** as the second argument. */ static void fts5DecodeAverages( int *pRc, /* IN/OUT: error code */ Fts5Buffer *pBuf, const u8 *pBlob, int nBlob ){ int i = 0; const char *zSpace = ""; while( i<nBlob ){ u64 iVal; i += sqlite3Fts5GetVarint(&pBlob[i], &iVal); sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "%s%d", zSpace, (int)iVal); zSpace = " "; } } /* ** Buffer (a/n) is assumed to contain a list of serialized varints. Read ** each varint and append its string representation to buffer pBuf. Return ** after either the input buffer is exhausted or a 0 value is read. ** ** The return value is the number of bytes read from the input buffer. |
︙ | ︙ | |||
5340 5341 5342 5343 5344 5345 5346 | for(fts5DlidxLvlNext(&lvl); lvl.bEof==0; fts5DlidxLvlNext(&lvl)){ sqlite3Fts5BufferAppendPrintf(&rc, &s, " %d(%lld)", lvl.iLeafPgno, lvl.iRowid ); } }else if( iSegid==0 ){ if( iRowid==FTS5_AVERAGES_ROWID ){ | | | | 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 | for(fts5DlidxLvlNext(&lvl); lvl.bEof==0; fts5DlidxLvlNext(&lvl)){ sqlite3Fts5BufferAppendPrintf(&rc, &s, " %d(%lld)", lvl.iLeafPgno, lvl.iRowid ); } }else if( iSegid==0 ){ if( iRowid==FTS5_AVERAGES_ROWID ){ fts5DecodeAverages(&rc, &s, a, n); }else{ fts5DecodeStructure(&rc, &s, a, n); } }else{ Fts5Buffer term; /* Current term read from page */ int szLeaf; /* Offset of pgidx in a[] */ int iPgidxOff; int iPgidxPrev = 0; /* Previous value read from pgidx */ int iTermOff = 0; int iRowidOff = 0; int iOff; int nDoclist; memset(&term, 0, sizeof(Fts5Buffer)); if( n<4 ){ sqlite3Fts5BufferSet(&rc, &s, 7, (const u8*)"corrupt"); goto decode_out; }else{ iRowidOff = fts5GetU16(&a[0]); iPgidxOff = szLeaf = fts5GetU16(&a[2]); if( iPgidxOff<n ){ fts5GetVarint32(&a[iPgidxOff], iTermOff); } |
︙ | ︙ |
Changes to ext/fts5/fts5_main.c.
︙ | ︙ | |||
435 436 437 438 439 440 441 442 443 444 445 446 447 448 | */ #define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */ #define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */ #define FTS5_PLAN_SPECIAL 3 /* An internal query */ #define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */ #define FTS5_PLAN_SCAN 5 /* No usable constraint */ #define FTS5_PLAN_ROWID 6 /* (rowid = ?) */ /* ** Implementation of the xBestIndex method for FTS5 tables. Within the ** WHERE constraint, it searches for the following: ** ** 1. A MATCH constraint against the special column. ** 2. A MATCH constraint against the "rank" column. | > > > > > > > > > > > > > | 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 | */ #define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */ #define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */ #define FTS5_PLAN_SPECIAL 3 /* An internal query */ #define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */ #define FTS5_PLAN_SCAN 5 /* No usable constraint */ #define FTS5_PLAN_ROWID 6 /* (rowid = ?) */ /* ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this ** extension is currently being used by a version of SQLite too old to ** support index-info flags. In that case this function is a no-op. */ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ #if SQLITE_VERSION_NUMBER>=3008012 if( sqlite3_libversion_number()>=3008012 ){ pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; } #endif } /* ** Implementation of the xBestIndex method for FTS5 tables. Within the ** WHERE constraint, it searches for the following: ** ** 1. A MATCH constraint against the special column. ** 2. A MATCH constraint against the "rank" column. |
︙ | ︙ | |||
488 489 490 491 492 493 494 | struct Constraint { int op; /* Mask against sqlite3_index_constraint.op */ int fts5op; /* FTS5 mask for idxFlags */ int iCol; /* 0==rowid, 1==tbl, 2==rank */ int omit; /* True to omit this if found */ int iConsIndex; /* Index in pInfo->aConstraint[] */ } aConstraint[] = { | | > | > | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | struct Constraint { int op; /* Mask against sqlite3_index_constraint.op */ int fts5op; /* FTS5 mask for idxFlags */ int iCol; /* 0==rowid, 1==tbl, 2==rank */ int omit; /* True to omit this if found */ int iConsIndex; /* Index in pInfo->aConstraint[] */ } aConstraint[] = { {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_MATCH, 1, 1, -1}, {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_RANK, 2, 1, -1}, {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1}, {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE, FTS5_BI_ROWID_LE, 0, 0, -1}, {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE, FTS5_BI_ROWID_GE, 0, 0, -1}, }; |
︙ | ︙ | |||
542 543 544 545 546 547 548 549 550 551 552 553 554 555 | } } /* Calculate the estimated cost based on the flags set in idxFlags. */ bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH); if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){ pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0; }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; }else{ pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; } | > | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | } } /* Calculate the estimated cost based on the flags set in idxFlags. */ bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH); if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){ pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0; if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo); }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; }else{ pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; } |
︙ | ︙ | |||
1280 1281 1282 1283 1284 1285 1286 | ** ** The commands implemented by this function are documented in the "Special ** INSERT Directives" section of the documentation. It should be updated if ** more commands are added to this function. */ static int fts5SpecialInsert( Fts5Table *pTab, /* Fts5 table object */ | | < | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > < > > > > > > > > | > > > > > > > > > > > > > > > > | | | | | | > > | < < | | < | < > > | < > | > > | | | > | | < < > | < < < > | > > > > > > > > > | > > > > > | | > > > > | > | | > | | 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 | ** ** The commands implemented by this function are documented in the "Special ** INSERT Directives" section of the documentation. It should be updated if ** more commands are added to this function. */ static int fts5SpecialInsert( Fts5Table *pTab, /* Fts5 table object */ const char *zCmd, /* Text inserted into table-name column */ sqlite3_value *pVal /* Value inserted into rank column */ ){ Fts5Config *pConfig = pTab->pConfig; int rc = SQLITE_OK; int bError = 0; if( 0==sqlite3_stricmp("delete-all", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ fts5SetVtabError(pTab, "'delete-all' may only be used with a " "contentless or external content fts5 table" ); rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage); } }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NONE ){ fts5SetVtabError(pTab, "'rebuild' may not be used with a contentless fts5 table" ); rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5StorageRebuild(pTab->pStorage); } }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ rc = sqlite3Fts5StorageOptimize(pTab->pStorage); }else if( 0==sqlite3_stricmp("merge", zCmd) ){ int nMerge = sqlite3_value_int(pVal); rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ rc = sqlite3Fts5StorageIntegrity(pTab->pStorage); #ifdef SQLITE_DEBUG }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif }else{ rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError); } if( rc==SQLITE_OK ){ if( bError ){ rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0); } } } return rc; } static int fts5SpecialDelete( Fts5Table *pTab, sqlite3_value **apVal, sqlite3_int64 *piRowid ){ int rc = SQLITE_OK; int eType1 = sqlite3_value_type(apVal[1]); if( eType1==SQLITE_INTEGER ){ sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]); } return rc; } static void fts5StorageInsert( int *pRc, Fts5Table *pTab, sqlite3_value **apVal, i64 *piRowid ){ int rc = *pRc; if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid); } *pRc = rc; } /* ** This function is the implementation of the xUpdate callback used by ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be ** inserted, updated or deleted. ** ** A delete specifies a single argument - the rowid of the row to remove. ** ** Update and insert operations pass: ** ** 1. The "old" rowid, or NULL. ** 2. The "new" rowid. ** 3. Values for each of the nCol matchable columns. ** 4. Values for the two hidden columns (<tablename> and "rank"). */ static int fts5UpdateMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Size of argument array */ sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ Fts5Table *pTab = (Fts5Table*)pVtab; Fts5Config *pConfig = pTab->pConfig; int eType0; /* value_type() of apVal[0] */ int rc = SQLITE_OK; /* Return code */ /* A transaction must be open when this is called. */ assert( pTab->ts.eState==1 ); assert( pVtab->zErrMsg==0 ); assert( nArg==1 || nArg==(2+pConfig->nCol+2) ); assert( nArg==1 || sqlite3_value_type(apVal[1])==SQLITE_INTEGER || sqlite3_value_type(apVal[1])==SQLITE_NULL ); assert( pTab->pConfig->pzErrmsg==0 ); pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; /* Put any active cursors into REQUIRE_SEEK state. */ fts5TripCursors(pTab); eType0 = sqlite3_value_type(apVal[0]); if( eType0==SQLITE_NULL && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL ){ /* A "special" INSERT op. These are handled separately. */ const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]); if( pConfig->eContent!=FTS5_CONTENT_NORMAL && 0==sqlite3_stricmp("delete", z) ){ rc = fts5SpecialDelete(pTab, apVal, pRowid); }else{ rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); } }else{ /* A regular INSERT, UPDATE or DELETE statement. The trick here is that ** any conflict on the rowid value must be detected before any ** modifications are made to the database file. There are 4 cases: ** ** 1) DELETE ** 2) UPDATE (rowid not modified) ** 3) UPDATE (rowid modified) ** 4) INSERT ** ** Cases 3 and 4 may violate the rowid constraint. */ int eConflict = sqlite3_vtab_on_conflict(pConfig->db); assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL ); assert( nArg!=1 || eType0==SQLITE_INTEGER ); /* Filter out attempts to run UPDATE or DELETE on contentless tables. ** This is not suported. */ if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ pTab->base.zErrMsg = sqlite3_mprintf( "cannot %s contentless fts5 table: %s", (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName ); rc = SQLITE_ERROR; } /* Case 1: DELETE */ else if( nArg==1 ){ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel); } /* Case 2: INSERT */ else if( eType0!=SQLITE_INTEGER ){ /* If this is a REPLACE, first remove the current entry (if any) */ if( eConflict==SQLITE_REPLACE && sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew); } fts5StorageInsert(&rc, pTab, apVal, pRowid); } /* Case 2: UPDATE */ else{ i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ if( iOld!=iNew ){ if( eConflict==SQLITE_REPLACE ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew); } fts5StorageInsert(&rc, pTab, apVal, pRowid); }else{ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); } } }else{ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); fts5StorageInsert(&rc, pTab, apVal, pRowid); } } } pTab->pConfig->pzErrmsg = 0; return rc; } /* ** Implementation of xSync() method. */ |
︙ | ︙ | |||
2306 2307 2308 2309 2310 2311 2312 | int nArg, /* Number of args */ sqlite3_value **apVal /* Function arguments */ ){ assert( nArg==0 ); sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT); } | < < < < | < < < | 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 | int nArg, /* Number of args */ sqlite3_value **apVal /* Function arguments */ ){ assert( nArg==0 ); sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT); } static int fts5Init(sqlite3 *db){ static const sqlite3_module fts5Mod = { /* iVersion */ 2, /* xCreate */ fts5CreateMethod, /* xConnect */ fts5ConnectMethod, /* xBestIndex */ fts5BestIndexMethod, /* xDisconnect */ fts5DisconnectMethod, /* xDestroy */ fts5DestroyMethod, |
︙ | ︙ | |||
2343 2344 2345 2346 2347 2348 2349 | /* xRelease */ fts5ReleaseMethod, /* xRollbackTo */ fts5RollbackToMethod, }; int rc; Fts5Global *pGlobal = 0; | < < | 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 | /* xRelease */ fts5ReleaseMethod, /* xRollbackTo */ fts5RollbackToMethod, }; int rc; Fts5Global *pGlobal = 0; pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global)); if( pGlobal==0 ){ rc = SQLITE_NOMEM; }else{ void *p = (void*)pGlobal; memset(pGlobal, 0, sizeof(Fts5Global)); pGlobal->db = db; |
︙ | ︙ | |||
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 | db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 ); } } return rc; } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fts_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | > | 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 | db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 ); } } return rc; } /* ** The following functions are used to register the module with SQLite. If ** this module is being built as part of the SQLite core (SQLITE_CORE is ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly. ** ** Or, if this module is being built as a loadable extension, ** sqlite3Fts5Init() is omitted and the two standard entry points ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead. */ #ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fts_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ return fts5Init(db); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fts5_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ return fts5Init(db); } #else int sqlite3Fts5Init(sqlite3 *db){ return fts5Init(db); } #endif |
Changes to ext/fts5/fts5_storage.c.
︙ | ︙ | |||
388 389 390 391 392 393 394 | int rc2; sqlite3_bind_int64(pSeek, 1, iDel); if( sqlite3_step(pSeek)==SQLITE_ROW ){ int iCol; Fts5InsertCtx ctx; ctx.pStorage = p; ctx.iCol = -1; | | | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | int rc2; sqlite3_bind_int64(pSeek, 1, iDel); if( sqlite3_step(pSeek)==SQLITE_ROW ){ int iCol; Fts5InsertCtx ctx; ctx.pStorage = p; ctx.iCol = -1; rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol-1] ) continue; ctx.szCol = 0; rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, (const char*)sqlite3_column_text(pSeek, iCol), sqlite3_column_bytes(pSeek, iCol), |
︙ | ︙ | |||
545 546 547 548 549 550 551 | /* Delete the index records */ if( rc==SQLITE_OK ){ int iCol; Fts5InsertCtx ctx; ctx.pStorage = p; ctx.iCol = -1; | | | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | /* Delete the index records */ if( rc==SQLITE_OK ){ int iCol; Fts5InsertCtx ctx; ctx.pStorage = p; ctx.iCol = -1; rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol] ) continue; ctx.szCol = 0; rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, (const char*)sqlite3_value_text(apVal[iCol]), sqlite3_value_bytes(apVal[iCol]), |
︙ | ︙ | |||
635 636 637 638 639 640 641 | rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ i64 iRowid = sqlite3_column_int64(pScan, 0); sqlite3Fts5BufferZero(&buf); | | | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ i64 iRowid = sqlite3_column_int64(pScan, 0); sqlite3Fts5BufferZero(&buf); rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, (const char*)sqlite3_column_text(pScan, ctx.iCol+1), sqlite3_column_bytes(pScan, ctx.iCol+1), |
︙ | ︙ | |||
701 702 703 704 705 706 707 | *piRowid = sqlite3_last_insert_rowid(p->pConfig->db); } } return rc; } /* | | | | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | 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 | *piRowid = sqlite3_last_insert_rowid(p->pConfig->db); } } return rc; } /* ** Insert a new row into the FTS content table. */ int sqlite3Fts5StorageContentInsert( Fts5Storage *p, sqlite3_value **apVal, i64 *piRowid ){ Fts5Config *pConfig = p->pConfig; int rc = SQLITE_OK; /* Insert the new row into the %_content table. */ if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){ *piRowid = sqlite3_value_int64(apVal[1]); }else{ rc = fts5StorageNewRowid(p, piRowid); } }else{ sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */ int i; /* Counter variable */ #if 0 if( eConflict==SQLITE_REPLACE ){ eStmt = FTS5_STMT_REPLACE_CONTENT; rc = fts5StorageDeleteFromIndex(p, sqlite3_value_int64(apVal[1])); }else{ eStmt = FTS5_STMT_INSERT_CONTENT; } #endif if( rc==SQLITE_OK ){ rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0); } for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ rc = sqlite3_bind_value(pInsert, i, apVal[i]); } if( rc==SQLITE_OK ){ sqlite3_step(pInsert); rc = sqlite3_reset(pInsert); } *piRowid = sqlite3_last_insert_rowid(pConfig->db); } return rc; } /* ** Insert new entries into the FTS index and %_docsize table. */ int sqlite3Fts5StorageIndexInsert( Fts5Storage *p, sqlite3_value **apVal, i64 iRowid ){ Fts5Config *pConfig = p->pConfig; int rc = SQLITE_OK; /* Return code */ Fts5InsertCtx ctx; /* Tokenization callback context object */ Fts5Buffer buf; /* Buffer used to build up %_docsize blob */ memset(&buf, 0, sizeof(Fts5Buffer)); ctx.pStorage = p; rc = fts5StorageLoadTotals(p, 1); if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); } for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, (const char*)sqlite3_value_text(apVal[ctx.iCol+2]), sqlite3_value_bytes(apVal[ctx.iCol+2]), (void*)&ctx, fts5StorageInsertCallback ); } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; } p->nTotalRow++; /* Write the %_docsize record */ if( rc==SQLITE_OK ){ rc = fts5StorageInsertDocsize(p, iRowid, &buf); } sqlite3_free(buf.p); /* Write the averages record */ if( rc==SQLITE_OK ){ rc = fts5StorageSaveTotals(p); } |
︙ | ︙ |
Changes to ext/fts5/fts5_tcl.c.
︙ | ︙ | |||
972 973 974 975 976 977 978 | static int f5tTokenHash( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | < | 972 973 974 975 976 977 978 979 980 981 982 983 984 985 | static int f5tTokenHash( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char *z; int n; unsigned int iVal; int nSlot; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "NSLOT TOKEN"); |
︙ | ︙ |
Changes to ext/fts5/fts5_vocab.c.
︙ | ︙ | |||
398 399 400 401 402 403 404 | sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; int rc; const int flags = FTS5INDEX_QUERY_SCAN; fts5VocabResetCursor(pCsr); | | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; int rc; const int flags = FTS5INDEX_QUERY_SCAN; fts5VocabResetCursor(pCsr); rc = sqlite3Fts5IndexQuery(pCsr->pIndex, 0, 0, flags, 0, &pCsr->pIter); if( rc==SQLITE_OK ){ rc = fts5VocabNextMethod(pCursor); } return rc; } |
︙ | ︙ |
Changes to ext/fts5/fts5parse.y.
︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 72 73 74 75 76 | %left OR. %left AND. %left NOT. %left TERM. %left COLON. input ::= expr(X). { sqlite3Fts5ParseFinished(pParse, X); } %type cnearset {Fts5ExprNode*} %type expr {Fts5ExprNode*} %type exprlist {Fts5ExprNode*} %destructor cnearset { sqlite3Fts5ParseNodeFree($$); } %destructor expr { sqlite3Fts5ParseNodeFree($$); } %destructor exprlist { sqlite3Fts5ParseNodeFree($$); } | > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | %left OR. %left AND. %left NOT. %left TERM. %left COLON. input ::= expr(X). { sqlite3Fts5ParseFinished(pParse, X); } %destructor input { (void)pParse; } %type cnearset {Fts5ExprNode*} %type expr {Fts5ExprNode*} %type exprlist {Fts5ExprNode*} %destructor cnearset { sqlite3Fts5ParseNodeFree($$); } %destructor expr { sqlite3Fts5ParseNodeFree($$); } %destructor exprlist { sqlite3Fts5ParseNodeFree($$); } |
︙ | ︙ | |||
97 98 99 100 101 102 103 | A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, X); } cnearset(A) ::= colset(X) COLON nearset(Y). { sqlite3Fts5ParseSetColset(pParse, Y, X); A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y); } | | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, X); } cnearset(A) ::= colset(X) COLON nearset(Y). { sqlite3Fts5ParseSetColset(pParse, Y, X); A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y); } %type colset {Fts5Colset*} %destructor colset { sqlite3_free($$); } %type colsetlist {Fts5Colset*} %destructor colsetlist { sqlite3_free($$); } colset(A) ::= LCP colsetlist(X) RCP. { A = X; } colset(A) ::= STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); } |
︙ | ︙ |
Changes to ext/fts5/test/fts5_common.tcl.
︙ | ︙ | |||
13 14 15 16 17 18 19 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. .. test] } source $testdir/tester.tcl catch { sqlite3_fts5_may_be_corrupt 0 | < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. .. test] } source $testdir/tester.tcl catch { sqlite3_fts5_may_be_corrupt 0 reset_db } proc fts5_test_poslist {cmd} { set res [list] for {set i 0} {$i < [$cmd xInstCount]} {incr i} { lappend res [string map {{ } .} [$cmd xInst $i]] |
︙ | ︙ |
Changes to ext/fts5/test/fts5al.test.
︙ | ︙ | |||
247 248 249 250 251 252 253 | INSERT INTO t3 VALUES('a one'); INSERT INTO t3 VALUES('a two'); INSERT INTO t3 VALUES('a three'); INSERT INTO t3 VALUES('a four'); INSERT INTO t3 VALUES('a five'); INSERT INTO t3(t3, rank) VALUES('rank', 'bm25()'); } | < > > > > > > > > > > > > > | 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 | INSERT INTO t3 VALUES('a one'); INSERT INTO t3 VALUES('a two'); INSERT INTO t3 VALUES('a three'); INSERT INTO t3 VALUES('a four'); INSERT INTO t3 VALUES('a five'); INSERT INTO t3(t3, rank) VALUES('rank', 'bm25()'); } do_execsql_test 4.3.2 { SELECT * FROM t3 WHERE t3 MATCH 'a' AND rank MATCH 'rowidmod(4)' ORDER BY rank ASC } { {a four} {a one} {a five} {a two} {a three} } do_execsql_test 4.3.3 { SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH 'rowidmod(3)' ORDER BY rank ASC } { {a three} 0 {a one} 1 {a four} 1 {a two} 2 {a five} 2 } do_execsql_test 4.3.4 { SELECT * FROM t3('a', 'rowidmod(4)') ORDER BY rank ASC; } { {a four} {a one} {a five} {a two} {a three} } do_execsql_test 4.3.5 { SELECT *, rank FROM t3('a', 'rowidmod(3)') ORDER BY rank ASC } { {a three} 0 {a one} 1 {a four} 1 {a two} 2 {a five} 2 } do_catchsql_test 4.4.3 { SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH 'xyz(3)' } {1 {no such function: xyz}} do_catchsql_test 4.4.4 { SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH NULL } {1 {parse error in rank function: }} |
︙ | ︙ |
Changes to ext/fts5/test/fts5fault6.test.
︙ | ︙ | |||
280 281 282 283 284 285 286 | #------------------------------------------------------------------------- catch { db close } breakpoint do_faultsim_test 6 -faults oom* -prep { sqlite_orig db test.db sqlite3_db_config_lookaside db 0 0 0 | < < | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | #------------------------------------------------------------------------- catch { db close } breakpoint do_faultsim_test 6 -faults oom* -prep { sqlite_orig db test.db sqlite3_db_config_lookaside db 0 0 0 } -test { faultsim_test_result {0 {}} {1 {initialization of fts5 failed: }} if {$testrc==0} { db eval { CREATE VIRTUAL TABLE temp.t1 USING fts5(x) } } db close } |
︙ | ︙ |
Added ext/fts5/test/fts5onepass.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 | # 2015 Sep 27 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5onepass # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts5 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE ft USING fts5(content); INSERT INTO ft(rowid, content) VALUES(1, '1 2 3'); INSERT INTO ft(rowid, content) VALUES(2, '4 5 6'); INSERT INTO ft(rowid, content) VALUES(3, '7 8 9'); } #------------------------------------------------------------------------- # Check that UPDATE and DELETE statements that feature "WHERE rowid=?" or # or "WHERE rowid=?" clauses do not use statement journals. But that other # DELETE and UPDATE statements do. # # Note: "MATCH ? AND rowid=?" does use a statement journal. # foreach {tn sql uses} { 1.1 { DELETE FROM ft } 1 1.2 { DELETE FROM ft WHERE rowid=? } 0 1.3 { DELETE FROM ft WHERE rowid=? } 0 1.4 { DELETE FROM ft WHERE ft MATCH '1' } 1 1.5 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1 1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1 2.1 { UPDATE ft SET content='a b c' } 1 2.2 { UPDATE ft SET content='a b c' WHERE rowid=? } 0 2.3 { UPDATE ft SET content='a b c' WHERE rowid=? } 0 2.4 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' } 1 2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1 2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1 } { do_test 1.$tn { sql_uses_stmt db $sql } $uses } #------------------------------------------------------------------------- # Check that putting a "DELETE/UPDATE ... WHERE rowid=?" statement in a # trigger program does not prevent the VM from using a statement # transaction. Even if the calling statement cannot hit a constraint. # do_execsql_test 2.0 { CREATE TABLE t1(x); CREATE TRIGGER t1_ai AFTER INSERT ON t1 BEGIN DELETE FROM ft WHERE rowid=new.x; END; CREATE TRIGGER t1_ad AFTER DELETE ON t1 BEGIN UPDATE ft SET content = 'a b c' WHERE rowid=old.x; END; CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 BEGIN DELETE FROM ft WHERE rowid=old.x; END; } foreach {tn sql uses} { 1 { INSERT INTO t1 VALUES(1) } 1 2 { DELETE FROM t1 WHERE x=4 } 1 3 { UPDATE t1 SET x=10 WHERE x=11 } 1 } { do_test 2.$tn { sql_uses_stmt db $sql } $uses } #------------------------------------------------------------------------- # Test that an "UPDATE ... WHERE rowid=?" works and does not corrupt the # index when it strikes a constraint. Both inside and outside a # transaction. # foreach {tn tcl1 tcl2} { 1 {} {} 2 { execsql BEGIN } { if {[sqlite3_get_autocommit db]==1} { error "transaction rolled back!" } execsql COMMIT } } { do_execsql_test 3.$tn.0 { DROP TABLE IF EXISTS ft2; CREATE VIRTUAL TABLE ft2 USING fts5(content); INSERT INTO ft2(rowid, content) VALUES(1, 'a b c'); INSERT INTO ft2(rowid, content) VALUES(2, 'a b d'); INSERT INTO ft2(rowid, content) VALUES(3, 'a b e'); } eval $tcl1 foreach {tn2 sql content} { 1 { UPDATE ft2 SET rowid=2 WHERE rowid=1 } { 1 {a b c} 2 {a b d} 3 {a b e} } 2 { INSERT INTO ft2(rowid, content) VALUES(4, 'a b f'); UPDATE ft2 SET rowid=5 WHERE rowid=4; UPDATE ft2 SET rowid=3 WHERE rowid=5; } { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } 3 { UPDATE ft2 SET rowid=3 WHERE rowid=4; -- matches 0 rows UPDATE ft2 SET rowid=2 WHERE rowid=3; } { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } 4 { INSERT INTO ft2(rowid, content) VALUES(4, 'a b g'); UPDATE ft2 SET rowid=-1 WHERE rowid=4; UPDATE ft2 SET rowid=3 WHERE rowid=-1; } {-1 {a b g} 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } 5 { DELETE FROM ft2 WHERE rowid=451; DELETE FROM ft2 WHERE rowid=-1; UPDATE ft2 SET rowid = 2 WHERE rowid = 1; } {1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } } { do_catchsql_test 3.$tn.$tn2.a $sql {1 {constraint failed}} do_execsql_test 3.$tn.$tn2.b { SELECT rowid, content FROM ft2 } $content do_execsql_test 3.$tn.$tn2.c { INSERT INTO ft2(ft2) VALUES('integrity-check'); } } eval $tcl2 } #------------------------------------------------------------------------- # Check that DELETE and UPDATE operations can be done without flushing # the in-memory hash table to disk. # reset_db do_execsql_test 4.1.1 { CREATE VIRTUAL TABLE ttt USING fts5(x); BEGIN; INSERT INTO ttt(rowid, x) VALUES(1, 'a b c'); INSERT INTO ttt(rowid, x) VALUES(2, 'a b c'); INSERT INTO ttt(rowid, x) VALUES(3, 'a b c'); COMMIT } do_test 4.1.2 { fts5_level_segs ttt } {1} do_execsql_test 4.2.1 { BEGIN; DELETE FROM ttt WHERE rowid=1; DELETE FROM ttt WHERE rowid=3; INSERT INTO ttt(rowid, x) VALUES(4, 'd e f'); INSERT INTO ttt(rowid, x) VALUES(5, 'd e f'); COMMIT; } {} do_test 4.2.2 { fts5_level_segs ttt } {2} do_execsql_test 4.3.1 { BEGIN; UPDATE ttt SET x = 'd e f' WHERE rowid = 2; UPDATE ttt SET x = 'A B C' WHERE rowid = 4; INSERT INTO ttt(rowid, x) VALUES(6, 'd e f'); COMMIT; } {} do_test 4.2.2 { fts5_level_segs ttt } {3} finish_test |
Added ext/fts5/test/fts5phrase.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 | # 2014 Jan 08 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Tests focused on phrase queries. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5phrase # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE t3 USING fts5(a, b, c); INSERT INTO t3 VALUES('d e a', 'd i j j f', 'i j i e b f h'); -- 1 INSERT INTO t3 VALUES('g a e', 'f g i g a', 'h d g i g h c'); -- 2 INSERT INTO t3 VALUES('e a d', 'e i h a f', 'c e h i f b i'); -- 3 INSERT INTO t3 VALUES('a g c', 'd j d j c', 'c d f j i g j'); -- 4 INSERT INTO t3 VALUES('b c b', 'j g c d f', 'j c j d g f b'); -- 5 INSERT INTO t3 VALUES('j a d', 'e b i h h', 'c c f g d i d'); -- 6 INSERT INTO t3 VALUES('a d f', 'h g i i i', 'e a g c i f b'); -- 7 INSERT INTO t3 VALUES('g f d', 'f c g b j', 'b b h h h j j'); -- 8 INSERT INTO t3 VALUES('f h g', 'c j f g j', 'd h d f e b h'); -- 9 INSERT INTO t3 VALUES('f h d', 'c i a d b', 'g b j b a d e'); -- 10 INSERT INTO t3 VALUES('j h h', 'j i h a g', 'd e i e a g j'); -- 11 INSERT INTO t3 VALUES('a b e', 'h g a g c', 'h c a a d e g'); -- 12 INSERT INTO t3 VALUES('a j g', 'i h i f i', 'a g h j g i b'); -- 13 INSERT INTO t3 VALUES('j h e', 'f e d i e', 'i d c f e d c'); -- 14 INSERT INTO t3 VALUES('d j d', 'd b i a c', 'g d h i d b e'); -- 15 INSERT INTO t3 VALUES('h j e', 'e b b c f', 'j a f g h d j'); -- 16 INSERT INTO t3 VALUES('c b j', 'c a b a i', 'h f i d a d c'); -- 17 INSERT INTO t3 VALUES('e e d', 'i d f c c', 'g i d a f e a'); -- 18 INSERT INTO t3 VALUES('e i g', 'e a b i h', 'i f d d a d f'); -- 19 INSERT INTO t3 VALUES('h g f', 'b h h j d', 'i f d e g j a'); -- 20 INSERT INTO t3 VALUES('e h f', 'j c b c f', 'j a j g h a c'); -- 21 INSERT INTO t3 VALUES('d c h', 'b g i c e', 'i i c d e h i'); -- 22 INSERT INTO t3 VALUES('a h i', 'a g d f f', 'e f i i b b h'); -- 23 INSERT INTO t3 VALUES('d d g', 'c c b c g', 'g c h e b c e'); -- 24 INSERT INTO t3 VALUES('a b b', 'b f a d i', 'd a h a b c i'); -- 25 INSERT INTO t3 VALUES('a f d', 'a j e a h', 'j i h j a i f'); -- 26 INSERT INTO t3 VALUES('d j d', 'h a d i a', 'h h f j h g a'); -- 27 INSERT INTO t3 VALUES('g a e', 'd g f a g', 'i d b c g g j'); -- 28 INSERT INTO t3 VALUES('j e h', 'g h j h g', 'd a e j a a h'); -- 29 INSERT INTO t3 VALUES('e j e', 'g e j g c', 'f c e b e e a'); -- 30 INSERT INTO t3 VALUES('h f f', 'i j g e c', 'j j f c a i j'); -- 31 INSERT INTO t3 VALUES('a g c', 'c g d b i', 'g h c b a a f'); -- 32 INSERT INTO t3 VALUES('c h i', 'j d h e e', 'a h i d c c j'); -- 33 INSERT INTO t3 VALUES('d a c', 'e d d b j', 'c e b b h i h'); -- 34 INSERT INTO t3 VALUES('d f h', 'c a f c c', 'j b b c c j f'); -- 35 INSERT INTO t3 VALUES('b g h', 'g c c c f', 'c g c f h e e'); -- 36 INSERT INTO t3 VALUES('f e a', 'b h f j h', 'j g h f d g f'); -- 37 INSERT INTO t3 VALUES('h f a', 'a e i j g', 'f d a f d f c'); -- 38 INSERT INTO t3 VALUES('f i c', 'f i i i i', 'e c f d h j f'); -- 39 INSERT INTO t3 VALUES('h h d', 'd i e d i', 'd f e i a h a'); -- 40 INSERT INTO t3 VALUES('f g c', 'd a f c h', 'b b g j c e g'); -- 41 INSERT INTO t3 VALUES('h i h', 'h d j d e', 'e d b b i e g'); -- 42 INSERT INTO t3 VALUES('b h i', 'j e i d a', 'j j h e e c a'); -- 43 INSERT INTO t3 VALUES('g i g', 'f c c f d', 'a c i c a d a'); -- 44 INSERT INTO t3 VALUES('c c f', 'a b j d b', 'c a e g f e c'); -- 45 INSERT INTO t3 VALUES('d h j', 'g c b j d', 'e a h f h j g'); -- 46 INSERT INTO t3 VALUES('a a d', 'j e j a i', 'i d c f f f b'); -- 47 INSERT INTO t3 VALUES('b g j', 'e c i h f', 'd d h b g a d'); -- 48 INSERT INTO t3 VALUES('c i a', 'a c c c c', 'e h i e h i e'); -- 49 INSERT INTO t3 VALUES('f f c', 'f f b i i', 'f f a j e c i'); -- 50 } proc pmatch {col expr} { return [expr {[string first $expr $col]>=0}] } db func pmatch pmatch foreach {tn cols tokens} { 1 a "c c" 2 b "c c" 3 c "c c" 4 {a b c} "c c" 5 {a b c} "b h" 6 {a b} "b h" 7 {a c} "b h" 8 {c a} "b h" 9 {c} "i e" 10 {b} "i e" 11 {a} "i e" } { set fts "{$cols}:[join $tokens +]" set where [list] foreach c $cols { lappend where "pmatch($c, '$tokens')" } set where [join $where " OR "] set res [db eval "SELECT rowid FROM t3 WHERE $where"] do_execsql_test "1.$tn.$fts->([llength $res] rows)" { SELECT rowid FROM t3($fts) } $res } do_execsql_test 2.0 { SELECT rowid, highlight(t3, 0, '*', '*'), highlight(t3, 1, '*', '*'), highlight(t3, 2, '*', '*') FROM t3('a:f+f') } { 31 {h *f f*} {i j g e c} {j j f c a i j} 50 {*f f* c} {f f b i i} {f f a j e c i} } finish_test |
Changes to ext/fts5/test/fts5prefix.test.
︙ | ︙ | |||
58 59 60 61 62 63 64 | foreach {tn q res} { 1 "SELECT rowid FROM t1 WHERE t1 MATCH '\xCA\xCB*'" 1 2 "SELECT rowid FROM t1 WHERE t1 MATCH '\u1234\u5678*'" 2 } { do_execsql_test 2.3.$tn $q $res } | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | foreach {tn q res} { 1 "SELECT rowid FROM t1 WHERE t1 MATCH '\xCA\xCB*'" 1 2 "SELECT rowid FROM t1 WHERE t1 MATCH '\u1234\u5678*'" 2 } { do_execsql_test 2.3.$tn $q $res } #------------------------------------------------------------------------- # Check that prefix queries with: # # * a column filter, and # * no prefix index. # # work Ok. # do_execsql_test 3.0 { CREATE VIRTUAL TABLE t3 USING fts5(a, b, c); INSERT INTO t3(t3, rank) VALUES('pgsz', 32); BEGIN; INSERT INTO t3 VALUES('acb ccc bba', 'cca bba bca', 'bbc ccc bca'); -- 1 INSERT INTO t3 VALUES('cbb cac cab', 'abb aac bba', 'aab ccc cac'); -- 2 INSERT INTO t3 VALUES('aac bcb aac', 'acb bcb caa', 'aca bab bca'); -- 3 INSERT INTO t3 VALUES('aab ccb ccc', 'aca cba cca', 'aca aac cbb'); -- 4 INSERT INTO t3 VALUES('bac aab bab', 'ccb bac cba', 'acb aba abb'); -- 5 INSERT INTO t3 VALUES('bab abc ccb', 'acb cba abb', 'cbb aaa cab'); -- 6 INSERT INTO t3 VALUES('cbb bbc baa', 'aab aca baa', 'bcc cca aca'); -- 7 INSERT INTO t3 VALUES('abc bba abb', 'cac abc cba', 'acc aac cac'); -- 8 INSERT INTO t3 VALUES('bbc bbc cab', 'bcb ccb cba', 'bcc cac acb'); -- 9 COMMIT; } foreach {tn match res} { 1 "a : c*" {1 2 4 6 7 9} 2 "b : c*" {1 3 4 5 6 8 9} 3 "c : c*" {1 2 4 6 7 8 9} 4 "a : b*" {1 3 5 6 7 8 9} 5 "b : b*" {1 2 3 5 7 9} 6 "c : b*" {1 3 7 9} 7 "a : a*" {1 3 4 5 6 8} 8 "b : a*" {2 3 4 6 7 8} 9 "c : a*" {2 3 4 5 6 7 8 9} } { do_execsql_test 3.1.$tn { SELECT rowid FROM t3($match) } $res } do_test 3.2 { expr srand(0) execsql { DELETE FROM t3 } for {set i 0} {$i < 1000} {incr i} { set a [fts5_rnddoc 3] set b [fts5_rnddoc 8] set c [fts5_rnddoc 20] execsql { INSERT INTO t3 VALUES($a, $b, $c) } } execsql { INSERT INTO t3(t3) VALUES('integrity-check') } } {} proc gmatch {col pattern} { expr {[lsearch -glob $col $pattern]>=0} } db func gmatch gmatch proc ghl {col pattern} { foreach t $col { if {[string match $pattern $t]} { lappend res "*$t*" } else { lappend res $t } } set res } db func ghl ghl set COLS(a) 0 set COLS(b) 1 set COLS(c) 2 for {set x 0} {$x<2} {incr x} { foreach {tn pattern} { 1 {xa*} 2 {xb*} 3 {xc*} 4 {xd*} 5 {xe*} 6 {xf*} 7 {xg*} 8 {xh*} 9 {xi*} 10 {xj*} } { foreach col {a b c} { # Check that the list of returned rowids is correct. # set res [db eval "SELECT rowid FROM t3 WHERE gmatch($col, '$pattern')"] set query "$col : $pattern" do_execsql_test 3.3.$x.$tn.$col.rowid { SELECT rowid FROM t3($query); } $res # Check that the highlight() function works. # set res [db eval \ "SELECT ghl($col, '$pattern') FROM t3 WHERE gmatch($col, '$pattern')" ] set idx $COLS($col) do_execsql_test 3.3.$x.$tn.$col.highlight { SELECT highlight(t3, $idx, '*', '*') FROM t3($query); } $res } foreach colset {{a b} {b c} {c a} {a c} {b a}} { # Check that the list of returned rowids is correct. # foreach {col1 col2} $colset {} set expr "gmatch($col1, '$pattern') OR gmatch($col2, '$pattern')" set res [db eval "SELECT rowid FROM t3 WHERE $expr"] set query "{$colset} : $pattern" do_execsql_test 3.3.$x.$tn.{$colset}.rowid { SELECT rowid FROM t3($query); } $res set resq "SELECT ghl($col1, '$pattern'), ghl($col2, '$pattern')" append resq " FROM t3 WHERE $expr" set res [db eval $resq] set idx1 $COLS($col1) set idx2 $COLS($col2) do_execsql_test 3.3.$x.$tn.{$colset}.highlight { SELECT highlight(t3, $idx1, '*', '*'), highlight(t3, $idx2, '*', '*') FROM t3($query) } $res } } execsql { INSERT INTO t3(t3) VALUES('optimize') } execsql { INSERT INTO t3(t3) VALUES('integrity-check') } } finish_test |
Changes to ext/fts5/test/fts5simple.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } | < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } #------------------------------------------------------------------------- # set doc "x x [string repeat {y } 50]z z" do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(x); INSERT INTO t1(t1, rank) VALUES('pgsz', 32); BEGIN; |
︙ | ︙ | |||
133 134 135 136 137 138 139 | COMMIT; } {} do_execsql_test 5.4 { SELECT rowid FROM tt WHERE tt MATCH 'a*'; } {1 2} | < < | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | COMMIT; } {} do_execsql_test 5.4 { SELECT rowid FROM tt WHERE tt MATCH 'a*'; } {1 2} do_execsql_test 5.5 { DELETE FROM tt; BEGIN; INSERT INTO tt VALUES('aa'); INSERT INTO tt VALUES('ab'); INSERT INTO tt VALUES('aa'); INSERT INTO tt VALUES('ab'); |
︙ | ︙ | |||
179 180 181 182 183 184 185 186 187 188 189 | do_catchsql_test 6.2 { SELECT * FROM xyz WHERE xyz MATCH '' } {1 {fts5: syntax error near ""}} do_catchsql_test 6.3 { SELECT * FROM xyz WHERE xyz MATCH NULL } {1 {fts5: syntax error near ""}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_catchsql_test 6.2 { SELECT * FROM xyz WHERE xyz MATCH '' } {1 {fts5: syntax error near ""}} do_catchsql_test 6.3 { SELECT * FROM xyz WHERE xyz MATCH NULL } {1 {fts5: syntax error near ""}} #------------------------------------------------------------------------- do_execsql_test 7.1 { CREATE VIRTUAL TABLE ft2 USING fts5(content); INSERT INTO ft2(rowid, content) VALUES(1, 'a b c'); INSERT INTO ft2(rowid, content) VALUES(2, 'a b d'); } do_catchsql_test 7.2 { BEGIN; UPDATE ft2 SET rowid=2 WHERE rowid=1; } {1 {constraint failed}} do_execsql_test 7.3 { COMMIT; INSERT INTO ft2(ft2) VALUES('integrity-check'); } {} do_execsql_test 7.4 { SELECT * FROM ft2; } {{a b c} {a b d}} #------------------------------------------------------------------------- # reset_db do_execsql_test 8.1 { CREATE VIRTUAL TABLE ft2 USING fts5(content); INSERT INTO ft2(rowid, content) VALUES(1, 'a b'); } do_execsql_test 8.2 { BEGIN; INSERT INTO ft2(rowid, content) VALUES(4, 'a x'); } do_execsql_test 8.3 { INSERT INTO ft2(ft2) VALUES('integrity-check'); } #------------------------------------------------------------------------- # Check that the "table function" syntax works. # reset_db do_execsql_test 9.1 { CREATE VIRTUAL TABLE ft2 USING fts5(content); INSERT INTO ft2(rowid, content) VALUES(1, 'a b'); INSERT INTO ft2(rowid, content) VALUES(2, 'a b c d'); INSERT INTO ft2(rowid, content) VALUES(3, 'c d e f'); } do_execsql_test 9.2 { SELECT rowid FROM ft2('a'); } {1 2} do_execsql_test 9.3 { SELECT rowid FROM ft2('b AND c'); } {2} #------------------------------------------------------------------------- # do_execsql_test 10.0 { CREATE VIRTUAL TABLE t3 USING fts5(a, b, c); INSERT INTO t3 VALUES('bac aab bab', 'c bac c', 'acb aba abb'); -- 1 INSERT INTO t3 VALUES('bab abc c', 'acb c abb', 'c aaa c'); -- 2 } do_execsql_test 10.1 { SELECT rowid FROM t3('c: c*'); } {2} #------------------------------------------------------------------------- # Test that character 0x1A is allowed in fts5 barewords. # do_test 11.0 { execsql "CREATE VIRTUAL TABLE t4 USING fts5(x, tokenize=\"ascii tokenchars '\x1A'\")" execsql " INSERT INTO t4 VALUES('a b c \x1A'); INSERT INTO t4 VALUES('a b c d\x1A'); INSERT INTO t4 VALUES('a b c \x1Ad'); INSERT INTO t4 VALUES('a b c d'); " } {} do_test 11.1 { execsql "SELECT rowid FROM t4('\x1A')" } {1} do_test 11.2 { execsql "SELECT rowid FROM t4('\x1A*')" } {1 3} do_test 11.3 { execsql "SELECT rowid FROM t4('d\x1A')" } {2} do_test 11.4 { catchsql "SELECT rowid FROM t4('d\x1B')" } {/fts5: syntax error/} do_test 11.5 { catchsql "SELECT rowid FROM t4('d\x19')" } {/fts5: syntax error/} finish_test |
Added ext/fts5/tool/fts5txt2db.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | proc usage {} { puts stderr "$::argv0 ?OPTIONS? DATABASE FILE1..." puts stderr "" puts stderr "Options are" puts stderr " -fts5" puts stderr " -fts4" puts stderr " -colsize <list of column sizes>" puts stderr { This script is designed to create fts4/5 tables with more than one column. The -colsize option should be set to a Tcl list of integer values, one for each column in the table. Each value is the number of tokens that will be inserted into the column value for each row. For example, setting the -colsize option to "5 10" creates an FTS table with 2 columns, with roughly 5 and 10 tokens per row in each, respectively. Each "FILE" argument should be a text file. The contents of these text files is split on whitespace characters to form a list of tokens. The first N1 tokens are used for the first column of the first row, where N1 is the first element of the -colsize list. The next N2 are used for the second column of the first row, and so on. Rows are added to the table until the entire list of tokens is exhausted. } exit -1 } set O(aColsize) [list 10 10 10] set O(tblname) t1 set O(fts) fts5 set options_with_values {-colsize} for {set i 0} {$i < [llength $argv]} {incr i} { set opt [lindex $argv $i] if {[string range $opt 0 0]!="-"} break if {[lsearch $options_with_values $opt]>=0} { incr i if {$i==[llength $argv]} usage set val [lindex $argv $i] } switch -- $opt { -colsize { set O(aColSize) $val } -fts4 { set O(fts) fts4 } -fts5 { set O(fts) fts5 } } } if {$i > [llength $argv]-2} usage set O(db) [lindex $argv $i] set O(files) [lrange $argv [expr $i+1] end] foreach {k v} [lrange $argv 0 end-2] { switch -- $k { -colsize { set O(aColSize) $v } -colsize { set O(aColSize) $v } } } sqlite3 db $O(db) load_static_extension db fts5 # Create the FTS table in the db. Return a list of the table columns. # proc create_table {} { global O set cols [list a b c d e f g h i j k l m n o p q r s t u v w x y z] set nCol [llength $O(aColsize)] set cols [lrange $cols 0 [expr $nCol-1]] set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $O(tblname) USING $O(fts) (" append sql [join $cols ,] append sql ");" db eval $sql return $cols } # Return a list of tokens from the named file. # proc readfile {file} { set fd [open $file] set data [read $fd] close $fd split $data } # Load all the data into a big list of tokens. # set tokens [list] foreach f $O(files) { set tokens [concat $tokens [readfile $f]] } set N [llength $tokens] set i 0 set cols [create_table] set sql "INSERT INTO $O(tblname) VALUES(\$[lindex $cols 0]" foreach c [lrange $cols 1 end] { append sql ", \$$c" } append sql ")" db eval BEGIN while {$i < $N} { foreach c $cols s $O(aColsize) { set $c [lrange $tokens $i [expr $i+$s-1]] incr i $s } db eval $sql } db eval COMMIT |
Changes to ext/fts5/tool/mkfts5c.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/bin/sh # restart with tclsh \ exec tclsh "$0" "$@" set srcdir [file dirname [file dirname [info script]]] set G(src) [string map [list %dir% $srcdir] { %dir%/fts5.h %dir%/fts5Int.h fts5parse.h %dir%/fts5_aux.c %dir%/fts5_buffer.c %dir%/fts5_config.c %dir%/fts5_expr.c %dir%/fts5_hash.c %dir%/fts5_index.c %dir%/fts5_main.c %dir%/fts5_storage.c %dir%/fts5_tokenize.c %dir%/fts5_unicode2.c %dir%/fts5_varint.c %dir%/fts5_vocab.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 | #!/bin/sh # restart with tclsh \ exec tclsh "$0" "$@" set srcdir [file dirname [file dirname [info script]]] set G(src) [string map [list %dir% $srcdir] { %dir%/fts5.h %dir%/fts5Int.h fts5parse.h fts5parse.c %dir%/fts5_aux.c %dir%/fts5_buffer.c %dir%/fts5_config.c %dir%/fts5_expr.c %dir%/fts5_hash.c %dir%/fts5_index.c %dir%/fts5_main.c %dir%/fts5_storage.c %dir%/fts5_tokenize.c %dir%/fts5_unicode2.c %dir%/fts5_varint.c %dir%/fts5_vocab.c }] set G(hdr) { #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif #if defined(NDEBUG) && defined(SQLITE_DEBUG) # undef NDEBUG #endif } set G(footer) { #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ } #------------------------------------------------------------------------- # Read and return the entire contents of text file $zFile from disk. # proc readfile {zFile} { set fd [open $zFile] |
︙ | ︙ | |||
83 84 85 86 87 88 89 | set sub_map [list --FTS5-SOURCE-ID-- [fts5_source_id $::srcdir]] if {$zTail=="fts5parse.c"} { lappend sub_map yy fts5yy YY fts5YY TOKEN FTS5TOKEN } foreach line [split $data "\n"] { if {[regexp {^#include.*fts5} $line]} continue | > | > < < < < | 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 | set sub_map [list --FTS5-SOURCE-ID-- [fts5_source_id $::srcdir]] if {$zTail=="fts5parse.c"} { lappend sub_map yy fts5yy YY fts5YY TOKEN FTS5TOKEN } foreach line [split $data "\n"] { if {[regexp {^#include.*fts5} $line]} continue if { ![regexp { sqlite3Fts5Init\(} $line] && [regexp {^(const )?[a-zA-Z][a-zA-Z0-9]* [*]?sqlite3Fts5} $line] } { set line "static $line" } set line [string map $sub_map $line] puts $G(fd) $line } } proc fts5c_close {} { global G puts -nonewline $G(fd) $G(footer) if {$G(fd)!="stdout"} { close $G(fd) } } fts5c_init fts5.c foreach f $G(src) { fts5c_printfile $f } fts5c_close |
Changes to ext/misc/json1.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** For the time being, all JSON is stored as pure text. (We might add ** a JSONB type in the future which stores a binary encoding of JSON in ** a BLOB, but there is no support for JSONB in the current implementation. ** This implementation parses JSON text at 250 MB/s, so it is hard to see ** how JSONB might improve on that.) */ #if !defined(_SQLITEINT_H_) #include "sqlite3ext.h" #endif SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <ctype.h> | > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** ** For the time being, all JSON is stored as pure text. (We might add ** a JSONB type in the future which stores a binary encoding of JSON in ** a BLOB, but there is no support for JSONB in the current implementation. ** This implementation parses JSON text at 250 MB/s, so it is hard to see ** how JSONB might improve on that.) */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) #if !defined(_SQLITEINT_H_) #include "sqlite3ext.h" #endif SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <ctype.h> |
︙ | ︙ | |||
1933 1934 1935 1936 1937 1938 1939 | 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ /**************************************************************************** | | | < < < | < < < < | 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 | 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ /**************************************************************************** ** The following routines are the only publically visible identifiers in this ** file. Call the following routines in order to register the various SQL ** functions and the virtual table implemented by this file. ****************************************************************************/ int sqlite3Json1Init(sqlite3 *db){ int rc = SQLITE_OK; unsigned int i; static const struct { const char *zName; int nArg; int flag; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); |
︙ | ︙ | |||
1983 1984 1985 1986 1987 1988 1989 | const char *zName; sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule }, }; #endif | < < > > > > > > > > > > > > > > > | 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 | const char *zName; sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule }, }; #endif for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, (void*)&aFunc[i].flag, aFunc[i].xFunc, 0, 0); } #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0); } #endif return rc; } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_json_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ return sqlite3Json1Init(db); } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */ |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 | #include <string.h> #include <stdio.h> #include "sqlite3.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) #include "sqlite3rbu.h" /* Maximum number of prepared UPDATE statements held by this module */ #define SQLITE_RBU_UPDATE_CACHESIZE 16 /* ** Swap two objects of type TYPE. */ | > > > > | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #include <string.h> #include <stdio.h> #include "sqlite3.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) #include "sqlite3rbu.h" #if defined(_WIN32_WCE) #include "windows.h" #endif /* Maximum number of prepared UPDATE statements held by this module */ #define SQLITE_RBU_UPDATE_CACHESIZE 16 /* ** Swap two objects of type TYPE. */ |
︙ | ︙ | |||
2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 | assert( p->rc==SQLITE_OK ); p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED); if( p->rc==SQLITE_OK ){ p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE); } } /* ** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock ** on the database file. This proc moves the *-oal file to the *-wal path, ** then reopens the database file (this time in vanilla, non-oal, WAL mode). ** If an error occurs, leave an error code and error message in the rbu ** handle. */ | > > > > > > > > > > > > > > > > > > > > > > > > | 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 | assert( p->rc==SQLITE_OK ); p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED); if( p->rc==SQLITE_OK ){ p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE); } } #if defined(_WIN32_WCE) static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){ int nChar; LPWSTR zWideFilename; nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); if( nChar==0 ){ return 0; } zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) ); if( zWideFilename==0 ){ return 0; } memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0])); nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); if( nChar==0 ){ sqlite3_free(zWideFilename); zWideFilename = 0; } return zWideFilename; } #endif /* ** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock ** on the database file. This proc moves the *-oal file to the *-wal path, ** then reopens the database file (this time in vanilla, non-oal, WAL mode). ** If an error occurs, leave an error code and error message in the rbu ** handle. */ |
︙ | ︙ | |||
2412 2413 2414 2415 2416 2417 2418 | rbuFileSuffix3(zBase, zWal); rbuFileSuffix3(zBase, zOal); /* Re-open the databases. */ rbuObjIterFinalize(&p->objiter); sqlite3_close(p->dbMain); sqlite3_close(p->dbRbu); | < < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 | rbuFileSuffix3(zBase, zWal); rbuFileSuffix3(zBase, zOal); /* Re-open the databases. */ rbuObjIterFinalize(&p->objiter); sqlite3_close(p->dbMain); sqlite3_close(p->dbRbu); p->dbMain = 0; p->dbRbu = 0; #if defined(_WIN32_WCE) { LPWSTR zWideOal; LPWSTR zWideWal; zWideOal = rbuWinUtf8ToUnicode(zOal); if( zWideOal ){ zWideWal = rbuWinUtf8ToUnicode(zWal); if( zWideWal ){ if( MoveFileW(zWideOal, zWideWal) ){ p->rc = SQLITE_OK; }else{ p->rc = SQLITE_IOERR; } sqlite3_free(zWideWal); }else{ p->rc = SQLITE_IOERR_NOMEM; } sqlite3_free(zWideOal); }else{ p->rc = SQLITE_IOERR_NOMEM; } } #else p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK; #endif if( p->rc==SQLITE_OK ){ rbuOpenDatabase(p); rbuSetupCheckpoint(p, 0); } } } sqlite3_free(zWal); |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # rtree-5.*: Test DELETE # rtree-6.*: Test UPDATE # rtree-7.*: Test renaming an r-tree table. # rtree-8.*: Test constrained scans of r-tree data. # # rtree-12.*: Test that on-conflict clauses are supported. # rtree-13.*: Test that bug [d2889096e7bdeac6d] has been fixed. # ifcapable !rtree { finish_test return } | > > > > > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | # rtree-5.*: Test DELETE # rtree-6.*: Test UPDATE # rtree-7.*: Test renaming an r-tree table. # rtree-8.*: Test constrained scans of r-tree data. # # rtree-12.*: Test that on-conflict clauses are supported. # rtree-13.*: Test that bug [d2889096e7bdeac6d] has been fixed. # rtree-14.*: Test if a non-integer is inserted into the PK column of an # r-tree table, it is converted to an integer before being # inserted. Also that if a non-numeric is inserted into one # of the min/max dimension columns, it is converted to the # required type before being inserted. # ifcapable !rtree { finish_test return } |
︙ | ︙ | |||
530 531 532 533 534 535 536 537 538 | WITH r(x) AS ( SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) SELECT * FROM r CROSS JOIN t9 WHERE id=x; } {1 1 0.0 0.0 2 2 0.0 0.0} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | WITH r(x) AS ( SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) SELECT * FROM r CROSS JOIN t9 WHERE id=x; } {1 1 0.0 0.0 2 2 0.0 0.0} #------------------------------------------------------------------------- # Test if a non-integer is inserted into the PK column of an r-tree # table, it is converted to an integer before being inserted. Also # that if a non-numeric is inserted into one of the min/max dimension # columns, it is converted to the required type before being inserted. # do_execsql_test 14.1 { CREATE VIRTUAL TABLE t10 USING rtree(ii, x1, x2); } do_execsql_test 14.2 { INSERT INTO t10 VALUES(NULL, 1, 2); INSERT INTO t10 VALUES(NULL, 2, 3); INSERT INTO t10 VALUES('4xxx', 3, 4); INSERT INTO t10 VALUES(5.0, 4, 5); INSERT INTO t10 VALUES(6.4, 5, 6); } do_execsql_test 14.3 { SELECT * FROM t10; } { 1 1.0 2.0 2 2.0 3.0 4 3.0 4.0 5 4.0 5.0 6 5.0 6.0 } do_execsql_test 14.4 { DELETE FROM t10; INSERT INTO t10 VALUES(1, 'one', 'two'); INSERT INTO t10 VALUES(2, '52xyz', '81...'); } do_execsql_test 14.5 { SELECT * FROM t10; } { 1 0.0 0.0 2 52.0 81.0 } do_execsql_test 14.4 { DROP TABLE t10; CREATE VIRTUAL TABLE t10 USING rtree_i32(ii, x1, x2); INSERT INTO t10 VALUES(1, 'one', 'two'); INSERT INTO t10 VALUES(2, '52xyz', '81...'); INSERT INTO t10 VALUES(3, 42.3, 49.9); } do_execsql_test 14.5 { SELECT * FROM t10; } { 1 0 0 2 52 81 3 42 49 } finish_test |
Changes to main.mk.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ############################################################################### # The following macros should be defined before this script is # invoked: # # TOP The toplevel directory of the source tree. This is the # directory that contains this "Makefile.in" and the # "configure.in" script. # # BCC C Compiler and options for use in building executables that # will run on the platform that is doing the build. # # THREADLIB Specify any extra linker options needed to make the library # thread safe # # OPTS Extra compiler command-line options. # # EXE The suffix to add to executable files. ".exe" for windows # and "" for Unix. # # TCC C Compiler and options for use in building executables that | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ############################################################################### # The following macros should be defined before this script is # invoked: # # TOP The toplevel directory of the source tree. This is the # directory that contains this "Makefile.in" and the # "configure.in" script. # # BCC C Compiler and options for use in building executables that # will run on the platform that is doing the build. # # THREADLIB Specify any extra linker options needed to make the library # thread safe # # LIBS Extra libraries options # # OPTS Extra compiler command-line options. # # EXE The suffix to add to executable files. ".exe" for windows # and "" for Unix. # # TCC C Compiler and options for use in building executables that |
︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 | # This is how we compile # TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3 TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth TCCX += -I$(TOP)/ext/fts5 # Object files for the SQLite library. # LIBOBJ+= vdbe.o parse.o \ alter.o analyze.o attach.o auth.o \ backup.o bitvec.o btmutex.o btree.o build.o \ | > | > | | | 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 | # This is how we compile # TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3 TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth TCCX += -I$(TOP)/ext/fts5 THREADLIB += $(LIBS) # Object files for the SQLite library. # LIBOBJ+= vdbe.o parse.o \ alter.o analyze.o attach.o auth.o \ backup.o bitvec.o btmutex.o btree.o build.o \ callback.o complete.o ctime.o date.o dbstat.o delete.o expr.o \ fault.o fkey.o \ fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \ fts3_tokenize_vtab.o \ fts3_unicode.o fts3_unicode2.o \ fts3_write.o fts5.o func.o global.o hash.o \ icu.o insert.o journal.o json1.o legacy.o loadext.o \ main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \ memjournal.o \ mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \ notify.o opcodes.o os.o os_unix.o os_win.o \ pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \ random.o resolve.o rowset.o rtree.o select.o sqlite3rbu.o status.o \ table.o threads.o tokenize.o treeview.o trigger.o \ |
︙ | ︙ | |||
223 224 225 226 227 228 229 | $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c SRC += \ $(TOP)/ext/sqlrr/sqlrr.c SRC += \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/userauth/sqlite3userauth.h | < > > | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c SRC += \ $(TOP)/ext/sqlrr/sqlrr.c SRC += \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/userauth/sqlite3userauth.h SRC += \ $(TOP)/ext/rbu/sqlite3rbu.c \ $(TOP)/ext/rbu/sqlite3rbu.h SRC += \ $(TOP)/ext/misc/json1.c # FTS5 things # FTS5_HDR = \ $(TOP)/ext/fts5/fts5.h \ $(TOP)/ext/fts5/fts5Int.h \ |
︙ | ︙ | |||
319 320 321 322 323 324 325 | TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ | < | < | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/wholenumber.c \ $(TOP)/ext/misc/vfslog.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c TESTSRC2 = \ $(TOP)/src/attach.c \ |
︙ | ︙ | |||
377 378 379 380 381 382 383 | $(TOP)/src/whereexpr.c \ 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 \ | | > | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | $(TOP)/src/whereexpr.c \ 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 \ $(FTS5_SRC) # Header files used by all library source files. # HDR = \ $(TOP)/src/btree.h \ $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ |
︙ | ︙ | |||
434 435 436 437 438 439 440 | # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db | < < < < < < > > > > > > | | < | | | | | | | 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 | # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.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 FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h libsqlite3.a sqlite3$(EXE) libsqlite3.a: $(LIBOBJ) $(AR) libsqlite3.a $(LIBOBJ) $(RANLIB) libsqlite3.a sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \ $(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB) fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h $(TCCX) -o fuzzershell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(FUZZERSHELL_OPT) $(TOP)/tool/fuzzershell.c sqlite3.c \ $(TLIBS) $(THREADLIB) fuzzcheck$(EXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(TCCX) -o fuzzcheck$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) \ $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS) $(THREADLIB) mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) $(THREADLIB) MPTEST1=./mptester$(EXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20 MPTEST2=./mptester$(EXE) mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20 |
︙ | ︙ | |||
498 499 500 501 502 503 504 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # | | > > > > | 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 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # target_source: $(SRC) $(EXTHDR) $(TOP)/tool/vdbe-compress.tcl fts5.c rm -rf tsrc mkdir tsrc cp -f $(SRC) $(EXTHDR) tsrc rm tsrc/sqlite.h.in tsrc/parse.y tclsh $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c cp fts5.c fts5.h tsrc touch target_source sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl tclsh $(TOP)/tool/mksqlite3c.tcl cp tsrc/shell.c tsrc/sqlite3ext.h . echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c sqlite3ext.h: target_source cp tsrc/sqlite3ext.h . sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c echo '#line 1 "tclsqlite.c"' >>tclsqlite3.c |
︙ | ︙ | |||
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon cp $(TOP)/ext/fts5/fts5parse.y . rm -f fts5parse.h ./lemon $(OPTS) fts5parse.y fts5parse.h: fts5parse.c | > > > > > > > > | 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c fts5.o: fts5.c $(TCCX) -DSQLITE_CORE -c fts5.c json1.o: $(TOP)/ext/misc/json1.c $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon cp $(TOP)/ext/fts5/fts5parse.y . rm -f fts5parse.h ./lemon $(OPTS) fts5parse.y fts5parse.h: fts5parse.c |
︙ | ︙ | |||
697 698 699 700 701 702 703 | TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \ -o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB) | | | | 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 | TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \ -o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB) amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ -DSQLITE_ENABLE_FTS3=1 \ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
663 664 665 666 667 668 669 | rc = saveCursorKey(pCur); if( rc==SQLITE_OK ){ btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } | | | 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | rc = saveCursorKey(pCur); if( rc==SQLITE_OK ){ btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl|BTCF_AtLast); return rc; } /* Forward reference */ static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*); /* |
︙ | ︙ | |||
7647 7648 7649 7650 7651 7652 7653 | ** for which the pointer is stored within the content being copied. ** ** It is critical that the child page be defragmented before being ** copied into the parent, because if the parent is page 1 then it will ** by smaller than the child due to the database header, and so all the ** free space needs to be up front. */ | | | 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 | ** for which the pointer is stored within the content being copied. ** ** It is critical that the child page be defragmented before being ** copied into the parent, because if the parent is page 1 then it will ** by smaller than the child due to the database header, and so all the ** free space needs to be up front. */ assert( nNew==1 || CORRUPT_DB ); rc = defragmentPage(apNew[0]); testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
188 189 190 191 192 193 194 195 196 197 198 199 200 201 | OP_Transaction, /* Opcode */ iDb, /* P1 */ DbMaskTest(pParse->writeMask,iDb), /* P2 */ pParse->cookieValue[iDb], /* P3 */ db->aDb[iDb].pSchema->iGeneration /* P4 */ ); if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); } #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; i<pParse->nVtabLock; i++){ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]); sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB); } pParse->nVtabLock = 0; | > > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | OP_Transaction, /* Opcode */ iDb, /* P1 */ DbMaskTest(pParse->writeMask,iDb), /* P2 */ pParse->cookieValue[iDb], /* P3 */ db->aDb[iDb].pSchema->iGeneration /* P4 */ ); if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); VdbeComment((v, "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite)); } #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; i<pParse->nVtabLock; i++){ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]); sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB); } pParse->nVtabLock = 0; |
︙ | ︙ | |||
2078 2079 2080 2081 2082 2083 2084 | DbFixer sFix; Token *pName = 0; int iDb; sqlite3 *db = pParse->db; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); | < | | 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 | DbFixer sFix; Token *pName = 0; int iDb; sqlite3 *db = pParse->db; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); goto create_view_fail; } sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; if( p==0 || pParse->nErr ) goto create_view_fail; sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); |
︙ | ︙ | |||
3131 3132 3133 3134 3135 3136 3137 | }else{ sortOrderMask = 0; /* Ignore DESC */ } /* Analyze the list of expressions that form the terms of the index and ** report any errors. In the common case where the expression is exactly ** a table column, store that column in aiColumn[]. For general expressions, | | | 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 | }else{ sortOrderMask = 0; /* Ignore DESC */ } /* Analyze the list of expressions that form the terms of the index and ** report any errors. In the common case where the expression is exactly ** a table column, store that column in aiColumn[]. For general expressions, ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[]. ** ** TODO: Issue a warning if two or more columns of the index are identical. ** TODO: Issue a warning if the table primary key is used as part of the ** index key. */ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){ Expr *pCExpr; /* The i-th index expression */ |
︙ | ︙ | |||
3160 3161 3162 3163 3164 3165 3166 | ExprList *pCopy = sqlite3ExprListDup(db, pList, 0); pIndex->aColExpr = pCopy; if( !db->mallocFailed ){ assert( pCopy!=0 ); pListItem = &pCopy->a[i]; } } | | | | 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 | ExprList *pCopy = sqlite3ExprListDup(db, pList, 0); pIndex->aColExpr = pCopy; if( !db->mallocFailed ){ assert( pCopy!=0 ); pListItem = &pCopy->a[i]; } } j = XN_EXPR; pIndex->aiColumn[i] = XN_EXPR; pIndex->uniqNotNull = 0; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; }else if( pTab->aCol[j].notNull==0 ){ |
︙ | ︙ | |||
3214 3215 3216 3217 3218 3219 3220 | pIndex->azColl[i] = pPk->azColl[j]; pIndex->aSortOrder[i] = pPk->aSortOrder[j]; i++; } } assert( i==pIndex->nColumn ); }else{ | | | 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 | pIndex->azColl[i] = pPk->azColl[j]; pIndex->aSortOrder[i] = pPk->aSortOrder[j]; i++; } } assert( i==pIndex->nColumn ); }else{ pIndex->aiColumn[i] = XN_ROWID; pIndex->azColl[i] = "BINARY"; } sqlite3DefaultRowEst(pIndex); if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex); if( pTab==pParse->pNewTable ){ /* This routine has been called to create an automatic index as a |
︙ | ︙ |
Changes to src/ctime.c.
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | "ENABLE_FTS3", #endif #if SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif #if SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif #if SQLITE_ENABLE_ICU "ENABLE_ICU", #endif #if SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif #if SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif #if SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif | > > > > > > | 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 | "ENABLE_FTS3", #endif #if SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif #if SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif #if SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif #if SQLITE_ENABLE_ICU "ENABLE_ICU", #endif #if SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif #if SQLITE_ENABLE_JSON1 "ENABLE_JSON1", #endif #if SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif #if SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
407 408 409 410 411 412 413 | ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values. ** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); if( pWInfo==0 ) goto delete_from_cleanup; eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); | | | | 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 | ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values. ** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); if( pWInfo==0 ) goto delete_from_cleanup; eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); /* Keep track of the number of rows to be deleted */ if( db->flags & SQLITE_CountRows ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } /* Extract the rowid or primary key for the current row */ if( pPk ){ for(i=0; i<nPk; i++){ assert( pPk->aiColumn[i]>=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } iKey = iPk; }else{ iKey = pParse->nMem + 1; iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0); |
︙ | ︙ | |||
490 491 492 493 494 495 496 | } /* Set up a loop over the rowids/primary-keys that were found in the ** where-clause loop above. */ if( eOnePass!=ONEPASS_OFF ){ assert( nKey==nPk ); /* OP_Found will use an unpacked key */ | | | 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | } /* Set up a loop over the rowids/primary-keys that were found in the ** where-clause loop above. */ if( eOnePass!=ONEPASS_OFF ){ assert( nKey==nPk ); /* OP_Found will use an unpacked key */ if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ assert( pPk!=0 || pTab->pSelect!=0 ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } }else if( pPk ){ addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey); |
︙ | ︙ | |||
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 | /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, OE_Abort); sqlite3MayAbort(pParse); }else #endif { int count = (pParse->nested==0); /* True to count changes */ int iIdxNoSeek = -1; if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){ iIdxNoSeek = aiCurOnePass[1]; | > > > > | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, OE_Abort); assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); sqlite3MayAbort(pParse); if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){ pParse->isMultiWrite = 0; } }else #endif { int count = (pParse->nested==0); /* True to count changes */ int iIdxNoSeek = -1; if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){ iIdxNoSeek = aiCurOnePass[1]; |
︙ | ︙ | |||
850 851 852 853 854 855 856 | } nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; regBase = sqlite3GetTempRange(pParse, nCol); if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; for(j=0; j<nCol; j++){ if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] | | | 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 | } nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; regBase = sqlite3GetTempRange(pParse, nCol); if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; for(j=0; j<nCol; j++){ if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] && pPrior->aiColumn[j]!=XN_EXPR ){ /* This column was already computed by the previous index */ continue; } sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); /* If the column affinity is REAL but the number is an integer, then it ** might be stored in the table as an integer (using a compact |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
2439 2440 2441 2442 2443 2444 2445 | Parse *pParse, /* The parsing context */ Index *pIdx, /* The index whose column is to be loaded */ int iTabCur, /* Cursor pointing to a table row */ int iIdxCol, /* The column of the index to be loaded */ int regOut /* Store the index column value in this register */ ){ i16 iTabCol = pIdx->aiColumn[iIdxCol]; | | < < < < | | | | > > > > | 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 | Parse *pParse, /* The parsing context */ Index *pIdx, /* The index whose column is to be loaded */ int iTabCur, /* Cursor pointing to a table row */ int iIdxCol, /* The column of the index to be loaded */ int regOut /* Store the index column value in this register */ ){ i16 iTabCol = pIdx->aiColumn[iIdxCol]; if( iTabCol==XN_EXPR ){ assert( pIdx->aColExpr ); assert( pIdx->aColExpr->nExpr>iIdxCol ); pParse->iSelfTab = iTabCur; sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); } } /* ** Generate code to extract the value of the iCol-th column of a table. */ void sqlite3ExprCodeGetColumnOfTable( Vdbe *v, /* The VDBE under construction */ |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
248 249 250 251 252 253 254 255 256 257 258 259 260 261 | ** the default collation sequences for each column. */ int i, j; for(i=0; i<nCol; i++){ i16 iCol = pIdx->aiColumn[i]; /* Index of column in parent tbl */ char *zDfltColl; /* Def. collation for column */ char *zIdxCol; /* Name of indexed column */ /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ zDfltColl = pParent->aCol[iCol].zColl; if( !zDfltColl ){ zDfltColl = "BINARY"; } | > > | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | ** the default collation sequences for each column. */ int i, j; for(i=0; i<nCol; i++){ i16 iCol = pIdx->aiColumn[i]; /* Index of column in parent tbl */ char *zDfltColl; /* Def. collation for column */ char *zIdxCol; /* Name of indexed column */ if( iCol<0 ) break; /* No foreign keys against expression indexes */ /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ zDfltColl = pParent->aCol[iCol].zColl; if( !zDfltColl ){ zDfltColl = "BINARY"; } |
︙ | ︙ | |||
400 401 402 403 404 405 406 407 408 409 410 411 412 413 | ** none of the child key values are). */ if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; i<nCol; i++){ int iChild = aiCol[i]+1+regData; int iParent = pIdx->aiColumn[i]+1+regData; assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ /* The parent key is a composite key that includes the IPK column */ iParent = regData; } sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); | > | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | ** none of the child key values are). */ if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; i<nCol; i++){ int iChild = aiCol[i]+1+regData; int iParent = pIdx->aiColumn[i]+1+regData; assert( pIdx->aiColumn[i]>=0 ); assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ /* The parent key is a composite key that includes the IPK column */ iParent = regData; } sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); |
︙ | ︙ | |||
608 609 610 611 612 613 614 615 616 617 618 619 620 621 | pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0); }else{ Expr *pEq, *pAll = 0; Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pIdx!=0 ); for(i=0; i<pPk->nKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; pLeft = exprTableRegister(pParse, pTab, regData, iCol); pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0); pAll = sqlite3ExprAnd(db, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0); } | > | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0); }else{ Expr *pEq, *pAll = 0; Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pIdx!=0 ); for(i=0; i<pPk->nKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; assert( iCol>=0 ); pLeft = exprTableRegister(pParse, pTab, regData, iCol); pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0); pAll = sqlite3ExprAnd(db, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0); } |
︙ | ︙ | |||
927 928 929 930 931 932 933 934 935 936 937 938 939 940 | iCol = pFKey->aCol[0].iFrom; aiCol = &iCol; } for(i=0; i<pFKey->nCol; i++){ if( aiCol[i]==pTab->iPKey ){ aiCol[i] = -1; } #ifndef SQLITE_OMIT_AUTHORIZATION /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; | > | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 | iCol = pFKey->aCol[0].iFrom; aiCol = &iCol; } for(i=0; i<pFKey->nCol; i++){ if( aiCol[i]==pTab->iPKey ){ aiCol[i] = -1; } assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; |
︙ | ︙ | |||
1058 1059 1060 1061 1062 1063 1064 | for(p=pTab->pFKey; p; p=p->pNextFrom){ for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ | | > > > | 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | for(p=pTab->pFKey; p; p=p->pNextFrom){ for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; i<pIdx->nKeyCol; i++){ assert( pIdx->aiColumn[i]>=0 ); mask |= COLUMN_MASK(pIdx->aiColumn[i]); } } } } return mask; } |
︙ | ︙ | |||
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 | Token tToCol; /* Name of column in parent table */ int iFromCol; /* Idx of column in child table */ Expr *pEq; /* tFromCol = OLD.tToCol */ iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iFromCol>=0 ); assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) ); tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName; tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName; tToCol.n = sqlite3Strlen30(tToCol.z); tFromCol.n = sqlite3Strlen30(tFromCol.z); /* Create the expression "OLD.zToCol = zFromCol". It is important | > | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 | Token tToCol; /* Name of column in parent table */ int iFromCol; /* Idx of column in child table */ Expr *pEq; /* tFromCol = OLD.tToCol */ iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iFromCol>=0 ); assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName; tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName; tToCol.n = sqlite3Strlen30(tToCol.z); tFromCol.n = sqlite3Strlen30(tFromCol.z); /* Create the expression "OLD.zToCol = zFromCol". It is important |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
86 87 88 89 90 91 92 | db->mallocFailed = 1; return 0; } for(n=0; n<pIdx->nColumn; n++){ i16 x = pIdx->aiColumn[n]; if( x>=0 ){ pIdx->zColAff[n] = pTab->aCol[x].affinity; | | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | db->mallocFailed = 1; return 0; } for(n=0; n<pIdx->nColumn; n++){ i16 x = pIdx->aiColumn[n]; if( x>=0 ){ pIdx->zColAff[n] = pTab->aCol[x].affinity; }else if( x==XN_ROWID ){ pIdx->zColAff[n] = SQLITE_AFF_INTEGER; }else{ char aff; assert( x==XN_EXPR ); assert( pIdx->aColExpr!=0 ); aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); if( aff==0 ) aff = SQLITE_AFF_BLOB; pIdx->zColAff[n] = aff; } } pIdx->zColAff[n] = 0; |
︙ | ︙ | |||
256 257 258 259 260 261 262 | int memId; /* Register holding max rowid */ int addr; /* A VDBE address */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ /* This routine is never called during trigger-generation. It is ** only called from the top-level */ assert( pParse->pTriggerTab==0 ); | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | int memId; /* Register holding max rowid */ int addr; /* A VDBE address */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ /* This routine is never called during trigger-generation. It is ** only called from the top-level */ assert( pParse->pTriggerTab==0 ); assert( sqlite3IsToplevel(pParse) ); assert( v ); /* We failed long ago if this is not so */ for(p = pParse->pAinc; p; p = p->pNext){ pDb = &db->aDb[p->iDb]; memId = p->regCtr; assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); |
︙ | ︙ | |||
1404 1405 1406 1407 1408 1409 1410 | /* Create a record for this index entry as it should appear after ** the insert or update. Store that record in the aRegIdx[ix] register */ regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); for(i=0; i<pIdx->nColumn; i++){ int iField = pIdx->aiColumn[i]; int x; | | | | 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 | /* Create a record for this index entry as it should appear after ** the insert or update. Store that record in the aRegIdx[ix] register */ regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); for(i=0; i<pIdx->nColumn; i++){ int iField = pIdx->aiColumn[i]; int x; if( iField==XN_EXPR ){ pParse->ckBase = regNewData+1; sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); pParse->ckBase = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); }else{ if( iField==XN_ROWID || iField==pTab->iPKey ){ if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ x = regNewData; regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; }else{ x = iField + regNewData + 1; } sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); |
︙ | ︙ | |||
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 | } }else{ int x; /* Extract the PRIMARY KEY from the end of the index entry and ** store it in registers regR..regR+nPk-1 */ if( pIdx!=pPk ){ for(i=0; i<pPk->nKeyCol; i++){ x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, pTab->aCol[pPk->aiColumn[i]].zName)); } } if( isUpdate ){ | > | 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 | } }else{ int x; /* Extract the PRIMARY KEY from the end of the index entry and ** store it in registers regR..regR+nPk-1 */ if( pIdx!=pPk ){ for(i=0; i<pPk->nKeyCol; i++){ assert( pPk->aiColumn[i]>=0 ); x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, pTab->aCol[pPk->aiColumn[i]].zName)); } } if( isUpdate ){ |
︙ | ︙ | |||
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); for(i=0; i<pPk->nKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; if( i==(pPk->nKeyCol-1) ){ addrJump = addrUniqueOk; op = OP_Eq; } sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); | > | 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 | int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); for(i=0; i<pPk->nKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; assert( x>=0 ); if( i==(pPk->nKeyCol-1) ){ addrJump = addrUniqueOk; op = OP_Eq; } sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); |
︙ | ︙ | |||
1741 1742 1743 1744 1745 1746 1747 | if( pDest->onError!=pSrc->onError ){ return 0; /* Different conflict resolution strategies */ } for(i=0; i<pSrc->nKeyCol; i++){ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ return 0; /* Different columns indexed */ } | | | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 | if( pDest->onError!=pSrc->onError ){ return 0; /* Different conflict resolution strategies */ } for(i=0; i<pSrc->nKeyCol; i++){ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ return 0; /* Different columns indexed */ } if( pSrc->aiColumn[i]==XN_EXPR ){ assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, pDest->aColExpr->a[i].pExpr, -1)!=0 ){ return 0; /* Different expressions in the index */ } } if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){ |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #endif #ifdef SQLITE_ENABLE_RTREE # include "rtree.h" #endif #ifdef SQLITE_ENABLE_ICU # include "sqliteicu.h" #endif #ifndef SQLITE_AMALGAMATION /* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant ** contains the text of SQLITE_VERSION macro. */ const char sqlite3_version[] = SQLITE_VERSION; #endif | > > > > > > | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #endif #ifdef SQLITE_ENABLE_RTREE # include "rtree.h" #endif #ifdef SQLITE_ENABLE_ICU # include "sqliteicu.h" #endif #ifdef SQLITE_ENABLE_JSON1 int sqlite3Json1Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_FTS5 int sqlite3Fts5Init(sqlite3*); #endif #ifndef SQLITE_AMALGAMATION /* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant ** contains the text of SQLITE_VERSION macro. */ const char sqlite3_version[] = SQLITE_VERSION; #endif |
︙ | ︙ | |||
2964 2965 2966 2967 2968 2969 2970 | #ifdef SQLITE_ENABLE_FTS2 if( !db->mallocFailed && rc==SQLITE_OK ){ extern int sqlite3Fts2Init(sqlite3*); rc = sqlite3Fts2Init(db); } #endif | | > > > > > > > > > > > > | 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 | #ifdef SQLITE_ENABLE_FTS2 if( !db->mallocFailed && rc==SQLITE_OK ){ extern int sqlite3Fts2Init(sqlite3*); rc = sqlite3Fts2Init(db); } #endif #ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */ if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3Fts3Init(db); } #endif #ifdef SQLITE_ENABLE_FTS5 if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3Fts5Init(db); } #endif #ifdef SQLITE_ENABLE_ICU if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3IcuInit(db); } #endif #ifdef SQLITE_ENABLE_RTREE if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3RtreeInit(db); } #endif #ifdef SQLITE_ENABLE_DBSTAT_VTAB if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3DbstatRegister(db); } #endif #ifdef SQLITE_ENABLE_JSON1 if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3Json1Init(db); } #endif /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking ** mode. Doing nothing at all also makes NORMAL the default. */ #ifdef SQLITE_DEFAULT_LOCKING_MODE db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE; |
︙ | ︙ |
Changes to src/mutex_unix.c.
︙ | ︙ | |||
77 78 79 80 81 82 83 | } static int pthreadMutexNotheld(sqlite3_mutex *p){ return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0; } #endif /* | | > > | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | } static int pthreadMutexNotheld(sqlite3_mutex *p){ return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0; } #endif /* ** Try to provide a memory barrier operation, needed for initialization ** and also for the implementation of xShmBarrier in the VFS in cases ** where SQLite is compiled without mutexes. */ void sqlite3MemoryBarrier(void){ #if defined(SQLITE_MEMORY_BARRIER) SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) && GCC_VERSION>=4001000 __sync_synchronize(); #endif |
︙ | ︙ |
Changes to src/mutex_w32.c.
︙ | ︙ | |||
74 75 76 77 78 79 80 | static int winMutexNotheld(sqlite3_mutex *p){ DWORD tid = GetCurrentThreadId(); return winMutexNotheld2(p, tid); } #endif /* | | > > > > > | | 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 | static int winMutexNotheld(sqlite3_mutex *p){ DWORD tid = GetCurrentThreadId(); return winMutexNotheld2(p, tid); } #endif /* ** Try to provide a memory barrier operation, needed for initialization ** and also for the xShmBarrier method of the VFS in cases when SQLite is ** compiled without mutexes (SQLITE_THREADSAFE=0). */ void sqlite3MemoryBarrier(void){ #if defined(SQLITE_MEMORY_BARRIER) SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) __sync_synchronize(); #elif !defined(SQLITE_DISABLE_INTRINSIC) && \ defined(_MSC_VER) && _MSC_VER>=1300 _ReadWriteBarrier(); #elif defined(MemoryBarrier) MemoryBarrier(); #endif } /* ** Initialize and deinitialize the mutex subsystem. */ |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
1374 1375 1376 1377 1378 1379 1380 | /* Code that appears at the end of the integrity check. If no error ** messages have been generated, output OK. Otherwise output the ** error message */ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { | | > | | 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 | /* Code that appears at the end of the integrity check. If no error ** messages have been generated, output OK. Otherwise output the ** error message */ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { { OP_AddImm, 1, 0, 0}, /* 0 */ { OP_If, 1, 0, 0}, /* 1 */ { OP_String8, 0, 3, 0}, /* 2 */ { OP_ResultRow, 3, 1, 0}, }; int isQuick = (sqlite3Tolower(zLeft[0])=='q'); /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check", ** then iDb is set to the index of the database identified by <db>. |
︙ | ︙ | |||
1537 1538 1539 1540 1541 1542 1543 | ** or (2) the next entry has a different key */ if( IsUniqueIndex(pIdx) ){ int uniqOk = sqlite3VdbeMakeLabel(v); int jmp6; int kk; for(kk=0; kk<pIdx->nKeyCol; kk++){ int iCol = pIdx->aiColumn[kk]; | | | | 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 | ** or (2) the next entry has a different key */ if( IsUniqueIndex(pIdx) ){ int uniqOk = sqlite3VdbeMakeLabel(v); int jmp6; int kk; for(kk=0; kk<pIdx->nKeyCol; kk++){ int iCol = pIdx->aiColumn[kk]; assert( iCol!=XN_ROWID && iCol<pTab->nCol ); if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); VdbeCoverage(v); } jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); sqlite3VdbeGoto(v, uniqOk); sqlite3VdbeJumpHere(v, jmp6); sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, |
︙ | ︙ | |||
1576 1577 1578 1579 1580 1581 1582 | sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7); sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1); } #endif /* SQLITE_OMIT_BTREECOUNT */ } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); | | | | | 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 | sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7); sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1); } #endif /* SQLITE_OMIT_BTREECOUNT */ } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); sqlite3VdbeChangeP2(v, addr, -mxErr); sqlite3VdbeJumpHere(v, addr+1); sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); } break; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_UTF16 /* ** PRAGMA encoding |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
575 576 577 578 579 580 581 | int addr; int iLimit; if( pSelect->iOffset ){ iLimit = pSelect->iOffset+1; }else{ iLimit = pSelect->iLimit; } | | < | < | < | 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 | int addr; int iLimit; if( pSelect->iOffset ){ iLimit = pSelect->iOffset+1; }else{ iLimit = pSelect->iLimit; } addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); sqlite3VdbeJumpHere(v, addr); } } /* ** Add code to implement the OFFSET */ static void codeOffset( Vdbe *v, /* Generate code into this VM */ int iOffset, /* Register holding the offset counter */ int iContinue /* Jump here to skip the current record */ ){ if( iOffset>0 ){ sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v); VdbeComment((v, "OFFSET")); } } /* ** Add code that will check to make sure the N registers starting at iMem ** form a distinct entry. iTab is a sorting index that holds previously ** seen combinations of the N values. A new entry is made in iTab |
︙ | ︙ | |||
1811 1812 1813 1814 1815 1816 1817 | ** the reuse of the same limit and offset registers across multiple ** SELECT statements. */ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ Vdbe *v = 0; int iLimit = 0; int iOffset; | | | 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 | ** the reuse of the same limit and offset registers across multiple ** SELECT statements. */ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ Vdbe *v = 0; int iLimit = 0; int iOffset; int n; if( p->iLimit ) return; /* ** "LIMIT -1" always shows all rows. There is some ** controversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | } if( p->pOffset ){ p->iOffset = iOffset = ++pParse->nMem; pParse->nMem++; /* Allocate an extra register for limit+offset */ sqlite3ExprCode(pParse, p->pOffset, iOffset); sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); VdbeComment((v, "OFFSET counter")); | < | < < | < | 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 | } if( p->pOffset ){ p->iOffset = iOffset = ++pParse->nMem; pParse->nMem++; /* Allocate an extra register for limit+offset */ sqlite3ExprCode(pParse, p->pOffset, iOffset); sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); VdbeComment((v, "OFFSET counter")); sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0); sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1); VdbeComment((v, "LIMIT+OFFSET")); sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1); } } } #ifndef SQLITE_OMIT_COMPOUND_SELECT /* ** Return the appropriate collating sequence for the iCol-th column of |
︙ | ︙ | |||
2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 | } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); } explainSetInteger(iSub2, pParse->iNextSelectId); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; p->nSelectRow += pPrior->nSelectRow; | > > > > > | 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 | } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); if( p->iOffset ){ sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0); sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1); sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1); } } explainSetInteger(iSub2, pParse->iNextSelectId); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; p->nSelectRow += pPrior->nSelectRow; |
︙ | ︙ | |||
4217 4218 4219 4220 4221 4222 4223 | /* Look up every table named in the FROM clause of the select. If ** an entry of the FROM clause is a subquery instead of a table or view, ** then create a transient table structure to describe the subquery. */ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab; | | < < < | < < < < < | 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 | /* Look up every table named in the FROM clause of the select. If ** an entry of the FROM clause is a subquery instead of a table or view, ** then create a transient table structure to describe the subquery. */ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab; assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); if( pFrom->fg.isRecursive ) continue; assert( pFrom->pTab==0 ); #ifndef SQLITE_OMIT_CTE if( withExpand(pWalker, pFrom) ) return WRC_Abort; if( pFrom->pTab ) {} else #endif if( pFrom->zName==0 ){ #ifndef SQLITE_OMIT_SUBQUERY Select *pSel = pFrom->pSelect; |
︙ | ︙ | |||
4519 4520 4521 4522 4523 4524 4525 | static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Parse *pParse; int i; SrcList *pTabList; struct SrcList_item *pFrom; assert( p->selFlags & SF_Resolved ); | | | | | | | > | | | | | | < | 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 | static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Parse *pParse; int i; SrcList *pTabList; struct SrcList_item *pFrom; assert( p->selFlags & SF_Resolved ); assert( (p->selFlags & SF_HasTypeInfo)==0 ); p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; assert( pTab!=0 ); if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ /* A sub-query in the FROM clause of a SELECT */ Select *pSel = pFrom->pSelect; if( pSel ){ while( pSel->pPrior ) pSel = pSel->pPrior; selectAddColumnTypeAndCollation(pParse, pTab, pSel); } } } } #endif |
︙ | ︙ | |||
4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 | /* Try to flatten subqueries in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; int isAggSub; if( pSub==0 ) continue; isAggSub = (pSub->selFlags & SF_Aggregate)!=0; if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ /* This subquery can be absorbed into its parent. */ if( isAggSub ){ isAgg = 1; p->selFlags |= SF_Aggregate; } | > > > > > > > > > > | 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 | /* Try to flatten subqueries in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; int isAggSub; Table *pTab = pItem->pTab; if( pSub==0 ) continue; /* Catch mismatch in the declared columns of a view and the number of ** columns in the SELECT on the RHS */ if( pTab->nCol!=pSub->pEList->nExpr ){ sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d", pTab->nCol, pTab->zName, pSub->pEList->nExpr); goto select_end; } isAggSub = (pSub->selFlags & SF_Aggregate)!=0; if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ /* This subquery can be absorbed into its parent. */ if( isAggSub ){ isAgg = 1; p->selFlags |= SF_Aggregate; } |
︙ | ︙ |
Changes to src/shell.c.
︙ | ︙ | |||
2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 | sqlite3_free(zSql); fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val); } sqlite3_free(zSchemaTab); return 0; } /* ** If an input line begins with "." then invoke this routine to ** process that line. ** ** Return 1 on error, 2 to exit, and 0 otherwise. */ | > > > > > > > > > > > > > > > > | 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 | sqlite3_free(zSql); fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val); } sqlite3_free(zSchemaTab); return 0; } /* ** Print the current sqlite3_errmsg() value to stderr and return 1. */ static int shellDatabaseError(sqlite3 *db){ const char *zErr = sqlite3_errmsg(db); fprintf(stderr, "Error: %s\n", zErr); return 1; } /* ** Print an out-of-memory message to stderr and return 1. */ static int shellNomemError(void){ fprintf(stderr, "Error: out of memory\n"); return 1; } /* ** If an input line begins with "." then invoke this routine to ** process that line. ** ** Return 1 on error, 2 to exit, and 0 otherwise. */ |
︙ | ︙ | |||
3709 3710 3711 3712 3713 3714 3715 | sqlite3_stmt *pStmt; char **azResult; int nRow, nAlloc; char *zSql = 0; int ii; open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); | | > > > > | | > | | > > | > > > | | > > | > > | > > > > | > | 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 | sqlite3_stmt *pStmt; char **azResult; int nRow, nAlloc; char *zSql = 0; int ii; open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ) return shellDatabaseError(p->db); /* Create an SQL statement to query for the list of tables in the ** main and all attached databases where the table name matches the ** LIKE pattern bound to variable "?1". */ zSql = sqlite3_mprintf( "SELECT name FROM sqlite_master" " WHERE type IN ('table','view')" " AND name NOT LIKE 'sqlite_%%'" " AND name LIKE ?1"); while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue; if( strcmp(zDbName,"temp")==0 ){ zSql = sqlite3_mprintf( "%z UNION ALL " "SELECT 'temp.' || name FROM sqlite_temp_master" " WHERE type IN ('table','view')" " AND name NOT LIKE 'sqlite_%%'" " AND name LIKE ?1", zSql); }else{ zSql = sqlite3_mprintf( "%z UNION ALL " "SELECT '%q.' || name FROM \"%w\".sqlite_master" " WHERE type IN ('table','view')" " AND name NOT LIKE 'sqlite_%%'" " AND name LIKE ?1", zSql, zDbName, zDbName); } } rc = sqlite3_finalize(pStmt); if( zSql && rc==SQLITE_OK ){ zSql = sqlite3_mprintf("%z ORDER BY 1", zSql); if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); } sqlite3_free(zSql); if( !zSql ) return shellNomemError(); if( rc ) return shellDatabaseError(p->db); /* Run the SQL statement prepared by the above block. Store the results ** as an array of nul-terminated strings in azResult[]. */ nRow = nAlloc = 0; azResult = 0; if( nArg>1 ){ sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT); }else{ sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC); } while( sqlite3_step(pStmt)==SQLITE_ROW ){ if( nRow>=nAlloc ){ char **azNew; int n2 = nAlloc*2 + 10; azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2); if( azNew==0 ){ rc = shellNomemError(); break; } nAlloc = n2; azResult = azNew; } azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); if( 0==azResult[nRow] ){ rc = shellNomemError(); break; } nRow++; } if( sqlite3_finalize(pStmt)!=SQLITE_OK ){ rc = shellDatabaseError(p->db); } /* Pretty-print the contents of array azResult[] to the output */ if( rc==0 && nRow>0 ){ int len, maxlen = 0; int i, j; int nPrintCol, nPrintRow; for(i=0; i<nRow; i++){ len = strlen30(azResult[i]); if( len>maxlen ) maxlen = len; } nPrintCol = 80/(maxlen+2); if( nPrintCol<1 ) nPrintCol = 1; nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; for(i=0; i<nPrintRow; i++){ for(j=i; j<nRow; j+=nPrintRow){ char *zSp = j<nPrintRow ? "" : " "; fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:""); } fprintf(p->out, "\n"); } } for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]); sqlite3_free(azResult); }else if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){ static const struct { const char *zCtrlName; /* Name of a test-control option */ |
︙ | ︙ | |||
4615 4616 4617 4618 4619 4620 4621 | #else fprintf(stderr,"%s: Error: no database filename specified\n", Argv0); return 1; #endif } data.out = stdout; | < < < < < < < | 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 | #else fprintf(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 ){ open_db(&data, 0); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
4357 4358 4359 4360 4361 4362 4363 | const void *sqlite3_value_text16(sqlite3_value*); const void *sqlite3_value_text16le(sqlite3_value*); const void *sqlite3_value_text16be(sqlite3_value*); int sqlite3_value_type(sqlite3_value*); int sqlite3_value_numeric_type(sqlite3_value*); /* | | | 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 | const void *sqlite3_value_text16(sqlite3_value*); const void *sqlite3_value_text16le(sqlite3_value*); const void *sqlite3_value_text16be(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 ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. |
︙ | ︙ | |||
5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 | ** strategy. A cost of N indicates that the cost of the strategy is similar ** to a linear scan of an SQLite table with N rows. A cost of log(N) ** indicates that the expense of the operation is similar to that of a ** binary search on a unique indexed field of an SQLite table with N rows. ** ** ^The estimatedRows value is an estimate of the number of rows that ** will be returned by the strategy. ** ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info ** structure for SQLite version 3.8.2. If a virtual table extension is ** used with an SQLite version earlier than 3.8.2, the results of attempting ** to read or write the estimatedRows field are undefined (but are likely ** to included crashing the application). The estimatedRows field should ** therefore only be used if [sqlite3_libversion_number()] returns a | > > > > > > > > > > > > > > > | > > > | 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 | ** strategy. A cost of N indicates that the cost of the strategy is similar ** to a linear scan of an SQLite table with N rows. A cost of log(N) ** indicates that the expense of the operation is similar to that of a ** binary search on a unique indexed field of an SQLite table with N rows. ** ** ^The estimatedRows value is an estimate of the number of rows that ** will be returned by the strategy. ** ** The xBestIndex method may optionally populate the idxFlags field with a ** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - ** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite ** assumes that the strategy may visit at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as ** part of the same statement to delete or update a virtual table row and the ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback ** any database changes. In other words, if the xUpdate() returns ** SQLITE_CONSTRAINT, the database contents must be exactly as they were ** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not ** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by ** the xUpdate method are automatically rolled back by SQLite. ** ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info ** structure for SQLite version 3.8.2. If a virtual table extension is ** used with an SQLite version earlier than 3.8.2, the results of attempting ** to read or write the estimatedRows field are undefined (but are likely ** to included crashing the application). The estimatedRows field should ** therefore only be used if [sqlite3_libversion_number()] returns a ** value greater than or equal to 3008002. Similarly, the idxFlags field ** was added for version 3.8.12. It may therefore only be used if ** sqlite3_libversion_number() returns a value greater than or equal to ** 3008012. */ struct sqlite3_index_info { /* Inputs */ int nConstraint; /* Number of entries in aConstraint */ struct sqlite3_index_constraint { int iColumn; /* Column on left-hand side of constraint */ unsigned char op; /* Constraint operator */ |
︙ | ︙ | |||
5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 | int idxNum; /* Number used to identify the index */ char *idxStr; /* String, possibly obtained from sqlite3_malloc */ int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ int orderByConsumed; /* True if output is already ordered */ double estimatedCost; /* Estimated cost of using this index */ /* Fields below are only available in SQLite 3.8.2 and later */ sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ }; /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** ** These macros defined the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents ** an operator that is part of a constraint term in the wHERE clause of ** a query that uses a [virtual table]. | > > > > > > > | 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 | int idxNum; /* Number used to identify the index */ char *idxStr; /* String, possibly obtained from sqlite3_malloc */ int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ int orderByConsumed; /* True if output is already ordered */ double estimatedCost; /* Estimated cost of using this index */ /* Fields below are only available in SQLite 3.8.2 and later */ sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ /* Fields below are only available in SQLite 3.8.12 and later */ int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ }; /* ** CAPI3REF: Virtual Table Scan Flags */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** ** These macros defined the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents ** an operator that is part of a constraint term in the wHERE clause of ** a query that uses a [virtual table]. |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
192 193 194 195 196 197 198 199 200 201 202 203 204 205 | */ #if !defined(SQLITE_DISABLE_INTRINSIC) # if defined(_MSC_VER) && _MSC_VER>=1300 # if !defined(_WIN32_WCE) # include <intrin.h> # pragma intrinsic(_byteswap_ushort) # pragma intrinsic(_byteswap_ulong) # else # include <cmnintrin.h> # endif # endif #endif /* | > | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | */ #if !defined(SQLITE_DISABLE_INTRINSIC) # if defined(_MSC_VER) && _MSC_VER>=1300 # if !defined(_WIN32_WCE) # include <intrin.h> # pragma intrinsic(_byteswap_ushort) # pragma intrinsic(_byteswap_ulong) # pragma intrinsic(_ReadWriteBarrier) # else # include <cmnintrin.h> # endif # endif #endif /* |
︙ | ︙ | |||
1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 | /* Return true if index X is a PRIMARY KEY index */ #define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) /* Return true if index X is a UNIQUE index */ #define IsUniqueIndex(X) ((X)->onError!=OE_None) /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ struct IndexSample { void *p; /* Pointer to sampled record */ | > > > > > > | 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 | /* Return true if index X is a PRIMARY KEY index */ #define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) /* Return true if index X is a UNIQUE index */ #define IsUniqueIndex(X) ((X)->onError!=OE_None) /* The Index.aiColumn[] values are normally positive integer. But ** there are some negative values that have special meaning: */ #define XN_ROWID (-1) /* Indexed column is the rowid */ #define XN_EXPR (-2) /* Indexed column is an expression */ /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ struct IndexSample { void *p; /* Pointer to sampled record */ |
︙ | ︙ | |||
3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 | Select*,u8); TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8); TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); void sqlite3DeleteTrigger(sqlite3*, Trigger*); void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) #else # define sqlite3TriggersExist(B,C,D,E,F) 0 # define sqlite3DeleteTrigger(A,B) # define sqlite3DropTriggerPtr(A,B) # define sqlite3UnlinkAndDeleteTrigger(A,B,C) # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) # define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F) # define sqlite3TriggerList(X, Y) 0 # define sqlite3ParseToplevel(p) p # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 #endif int sqlite3JoinType(Parse*, Token*, Token*, Token*); void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); void sqlite3DeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION | > > | 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 | Select*,u8); TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8); TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); void sqlite3DeleteTrigger(sqlite3*, Trigger*); void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else # define sqlite3TriggersExist(B,C,D,E,F) 0 # define sqlite3DeleteTrigger(A,B) # define sqlite3DropTriggerPtr(A,B) # define sqlite3UnlinkAndDeleteTrigger(A,B,C) # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) # define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F) # define sqlite3TriggerList(X, Y) 0 # define sqlite3ParseToplevel(p) p # define sqlite3IsToplevel(p) 1 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 #endif int sqlite3JoinType(Parse*, Token*, Token*, Token*); void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); void sqlite3DeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
6565 6566 6567 6568 6569 6570 6571 | ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); | < < < < < < | 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 | ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_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*); static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, { "eval", sqlite3_eval_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, { "series", sqlite3_series_init }, { "spellfix", sqlite3_spellfix_init }, { "totype", sqlite3_totype_init }, { "wholenumber", sqlite3_wholenumber_init }, |
︙ | ︙ | |||
6614 6615 6616 6617 6618 6619 6620 | for(i=0; i<ArraySize(aExtension); i++){ if( strcmp(zName, aExtension[i].zExtName)==0 ) break; } if( i>=ArraySize(aExtension) ){ Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0); return TCL_ERROR; } | > | > > > | 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 | for(i=0; i<ArraySize(aExtension); i++){ if( strcmp(zName, aExtension[i].zExtName)==0 ) break; } if( i>=ArraySize(aExtension) ){ Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0); return TCL_ERROR; } if( aExtension[i].pInit ){ rc = aExtension[i].pInit(db, &zErrMsg, 0); }else{ rc = SQLITE_OK; } if( rc!=SQLITE_OK || zErrMsg ){ Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg, (char*)0); sqlite3_free(zErrMsg); return TCL_ERROR; } } |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 171 172 173 174 175 | #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_ATTACH Tcl_SetVar2(interp, "sqlite_options", "attach", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "attach", "1", TCL_GLOBAL_ONLY); #endif | > > > > > > | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_JSON1 Tcl_SetVar2(interp, "sqlite_options", "json1", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_ATTACH Tcl_SetVar2(interp, "sqlite_options", "attach", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "attach", "1", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ |
Changes to src/threads.c.
︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 72 73 74 75 76 | *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM; memset(p, 0, sizeof(*p)); p->xTask = xTask; p->pIn = pIn; if( sqlite3FaultSim(200) ){ rc = 1; }else{ rc = pthread_create(&p->tid, 0, xTask, pIn); } if( rc ){ p->done = 1; | > > > > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM; memset(p, 0, sizeof(*p)); p->xTask = xTask; p->pIn = pIn; /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a ** function that returns SQLITE_ERROR when passed the argument 200, that ** forces worker threads to run sequentially and deterministically ** for testing purposes. */ if( sqlite3FaultSim(200) ){ rc = 1; }else{ rc = pthread_create(&p->tid, 0, xTask, pIn); } if( rc ){ p->done = 1; |
︙ | ︙ | |||
147 148 149 150 151 152 153 | SQLiteThread *p; assert( ppThread!=0 ); assert( xTask!=0 ); *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM; | > > > > > | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | SQLiteThread *p; assert( ppThread!=0 ); assert( xTask!=0 ); *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM; /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a ** function that returns SQLITE_ERROR when passed the argument 200, that ** forces worker threads to run sequentially and deterministically ** (via the sqlite3FaultSim() term of the conditional) for testing ** purposes. */ if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){ memset(p, 0, sizeof(*p)); }else{ p->xTask = xTask; p->pIn = pIn; p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); if( p->tid==0 ){ memset(p, 0, sizeof(*p)); |
︙ | ︙ | |||
175 176 177 178 179 180 181 | int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ DWORD rc; BOOL bRc; assert( ppOut!=0 ); if( NEVER(p==0) ) return SQLITE_NOMEM; if( p->xTask==0 ){ | | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ DWORD rc; BOOL bRc; assert( ppOut!=0 ); if( NEVER(p==0) ) return SQLITE_NOMEM; if( p->xTask==0 ){ /* assert( p->id==GetCurrentThreadId() ); */ rc = WAIT_OBJECT_0; assert( p->tid==0 ); }else{ assert( p->id!=0 && p->id!=GetCurrentThreadId() ); rc = sqlite3Win32Wait((HANDLE)p->tid); assert( rc!=WAIT_IO_COMPLETION ); bRc = CloseHandle((HANDLE)p->tid); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
130 131 132 133 134 135 136 | int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */ int iEph = 0; /* Ephemeral table holding all primary key values */ int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ | | | | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */ int iEph = 0; /* Ephemeral table holding all primary key values */ int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid = 0; /* The old rowid */ int regNewRowid = 0; /* The new rowid */ int regNew = 0; /* Content of the NEW.* table in triggers */ int regOld = 0; /* Content of OLD.* table in triggers */ int regRowSet = 0; /* Rowset of rows to be updated */ int regKey = 0; /* composite PRIMARY KEY value */ memset(&sContext, 0, sizeof(sContext)); db = pParse->db; if( pParse->nErr || db->mallocFailed ){ |
︙ | ︙ | |||
296 297 298 299 300 301 302 | /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, 1, iDb); | < < < < < < < < < < < > | | | | | | | | | | | > | 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 | /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, 1, iDb); /* Allocate required registers. */ if( !IsVirtual(pTab) ){ regRowSet = ++pParse->nMem; regOldRowid = regNewRowid = ++pParse->nMem; if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; pParse->nMem += pTab->nCol; } if( chngKey || pTrigger || hasFK ){ regNewRowid = ++pParse->nMem; } regNew = pParse->nMem + 1; pParse->nMem += pTab->nCol; } /* Start the view context. */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If we are trying to update a view, realize that view into |
︙ | ︙ | |||
340 341 342 343 344 345 346 347 348 349 350 351 352 353 | /* Resolve the column names in all the expressions in the ** WHERE clause. */ if( sqlite3ResolveExprNames(&sNC, pWhere) ){ goto update_cleanup; } /* Begin the database scan */ if( HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur | > > > > > > > > > | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | /* Resolve the column names in all the expressions in the ** WHERE clause. */ if( sqlite3ResolveExprNames(&sNC, pWhere) ){ goto update_cleanup; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Virtual tables must be handled separately */ if( IsVirtual(pTab) ){ updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, pWhere, onError); goto update_cleanup; } #endif /* Begin the database scan */ if( HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur |
︙ | ︙ | |||
380 381 382 383 384 385 386 | addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); sqlite3VdbeSetP4KeyInfo(pParse, pPk); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur); if( pWInfo==0 ) goto update_cleanup; okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); for(i=0; i<nPk; i++){ | | | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); sqlite3VdbeSetP4KeyInfo(pParse, pPk); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur); if( pWInfo==0 ) goto update_cleanup; okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); for(i=0; i<nPk; i++){ assert( pPk->aiColumn[i]>=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], iPk+i); } if( okOnePass ){ sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; |
︙ | ︙ | |||
503 504 505 506 507 508 509 | ** the database after the BEFORE triggers are fired anyway (as the trigger ** may have modified them). So not loading those that are not going to ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); | < | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | ** the database after the BEFORE triggers are fired anyway (as the trigger ** may have modified them). So not loading those that are not going to ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); for(i=0; i<pTab->nCol; i++){ if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); }else{ j = aXRef[i]; if( j>=0 ){ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); |
︙ | ︙ | |||
681 682 683 684 685 686 687 | #undef pTrigger #endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Generate code for an UPDATE of a virtual table. ** | > > > > | | | < < | > | < | < < < < < < | < > | < < > | < > | > > | < < < < < < < < < < | | | < > > > > > | > > | > > > > > > > > > > > > > > | > | > > > > > > > | > > | > > > > | | > > > | > | | > > | | | > | > > > > | | | > > | < < | 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 | #undef pTrigger #endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Generate code for an UPDATE of a virtual table. ** ** There are two possible strategies - the default and the special ** "onepass" strategy. Onepass is only used if the virtual table ** implementation indicates that pWhere may match at most one row. ** ** The default strategy is to create an ephemeral table that contains ** for each row to be changed: ** ** (A) The original rowid of that row. ** (B) The revised rowid for the row. ** (C) The content of every column in the row. ** ** Then loop through the contents of this ephemeral table executing a ** VUpdate for each row. When finished, drop the ephemeral table. ** ** The "onepass" strategy does not use an ephemeral table. Instead, it ** stores the same values (A, B and C above) in a register array and ** makes a single invocation of VUpdate. */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ SrcList *pSrc, /* The virtual table to be modified */ Table *pTab, /* The virtual table */ ExprList *pChanges, /* The columns to change in the UPDATE statement */ Expr *pRowid, /* Expression used to recompute the rowid */ int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ Expr *pWhere, /* WHERE clause of the UPDATE statement */ int onError /* ON CONFLICT strategy */ ){ Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); WhereInfo *pWInfo; int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ int regArg; /* First register in VUpdate arg array */ int regRec; /* Register in which to assemble record */ int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ int bOnePass; /* True to use onepass strategy */ int addr; /* Address of OP_OpenEphemeral */ /* Allocate nArg registers to martial the arguments to VUpdate. Then ** create and open the ephemeral table in which the records created from ** these arguments will be temporarily stored. */ assert( v ); ephemTab = pParse->nTab++; addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg); regArg = pParse->nMem + 1; pParse->nMem += nArg; regRec = ++pParse->nMem; regRowid = ++pParse->nMem; /* Start scanning the virtual table */ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0); if( pWInfo==0 ) return; /* Populate the argument registers. */ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); if( pRowid ){ sqlite3ExprCode(pParse, pRowid, regArg+1); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); } 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); } } bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); if( bOnePass ){ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded ** above. Also, if this is a top-level parse (not a trigger), clear the ** multi-write flag so that the VM does not open a statement journal */ sqlite3VdbeChangeToNoop(v, addr); 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 */ sqlite3WhereEnd(pWInfo); /* Begin scannning through the ephemeral table. */ addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); /* Extract arguments from the current row of the ephemeral table and ** invoke the VUpdate method. */ for(i=0; i<nArg; i++){ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i); } } sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, nArg, regArg, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); sqlite3MayAbort(pParse); /* End of the ephemeral table scan. Or, if using the onepass strategy, ** jump to here if the scan visited zero rows. */ if( bOnePass==0 ){ sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); }else{ sqlite3WhereEnd(pWInfo); } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
Changes to src/vdbe.c.
︙ | ︙ | |||
5668 5669 5670 5671 5672 5673 5674 | if( pIn1->u.i<pIn2->u.i){ pIn1->u.i = pIn2->u.i; } break; } #endif /* SQLITE_OMIT_AUTOINCREMENT */ | | | | | | > > > | | | | > | < < | > > > | > | | | | 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 | if( pIn1->u.i<pIn2->u.i){ pIn1->u.i = pIn2->u.i; } break; } #endif /* SQLITE_OMIT_AUTOINCREMENT */ /* Opcode: IfPos P1 P2 P3 * * ** Synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 ** ** Register P1 must contain an integer. ** If the value of register P1 is 1 or greater, subtract P3 from the ** value in P1 and jump to P2. ** ** If the initial value of register P1 is less than 1, then the ** value is unchanged and control passes through to the next instruction. */ case OP_IfPos: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); VdbeBranchTaken( pIn1->u.i>0, 2); if( pIn1->u.i>0 ){ pIn1->u.i -= pOp->p3; goto jump_to_p2; } break; } /* Opcode: SetIfNotPos P1 P2 P3 * * ** Synopsis: if r[P1]<=0 then r[P2]=P3 ** ** Register P1 must contain an integer. ** If the value of register P1 is not positive (if it is less than 1) then ** set the value of register P2 to be the integer P3. */ case OP_SetIfNotPos: { /* in1, in2 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); if( pIn1->u.i<=0 ){ pOut = out2Prerelease(p, pOp); pOut->u.i = pOp->p3; } break; } /* Opcode: IfNotZero P1 P2 P3 * * ** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 ** ** Register P1 must contain an integer. If the content of register P1 is ** initially nonzero, then subtract P3 from the value in register P1 and ** jump to P2. If register P1 is initially zero, leave it unchanged ** and fall through. */ case OP_IfNotZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); VdbeBranchTaken(pIn1->u.i<0, 2); if( pIn1->u.i ){ pIn1->u.i -= pOp->p3; goto jump_to_p2; } break; } /* Opcode: DecrJumpZero P1 P2 * * * ** Synopsis: if (--r[P1])==0 goto P2 |
︙ | ︙ |
Changes to src/vdbeblob.c.
︙ | ︙ | |||
244 245 246 247 248 249 250 | } } #endif for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int j; for(j=0; j<pIdx->nKeyCol; j++){ /* FIXME: Be smarter about indexes that use expressions */ | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | } } #endif for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int j; for(j=0; j<pIdx->nKeyCol; j++){ /* FIXME: Be smarter about indexes that use expressions */ if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==XN_EXPR ){ zFault = "indexed"; } } } if( zFault ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault); |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 | /* Invoke the xBegin method. If successful, add the vtab to the ** sqlite3.aVTrans[] array. */ rc = growVTrans(db); if( rc==SQLITE_OK ){ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ addToVTrans(db, pVTab); } } } return rc; } /* | > > | 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 | /* Invoke the xBegin method. If successful, add the vtab to the ** sqlite3.aVTrans[] array. */ rc = growVTrans(db); if( rc==SQLITE_OK ){ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ int iSvpt = db->nStatement + db->nSavepoint; addToVTrans(db, pVTab); if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1); } } } return rc; } /* |
︙ | ︙ | |||
1139 1140 1141 1142 1143 1144 1145 | /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; | | | 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 | /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ sqlite3DeleteColumnNames(db, pTab); sqlite3VtabClear(db, pTab); sqlite3DbFree(db, pTab); pMod->pEpoTab = 0; } } |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 95 96 | ** Any cursors returned will have been opened for writing. ** ** aiCur[0] and aiCur[1] both get -1 if the where-clause logic is ** unable to use the ONEPASS optimization. */ int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){ memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2); return pWInfo->eOnePass; } /* ** Move the content of pSrc into pDest */ static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){ | > > > > > > > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | ** Any cursors returned will have been opened for writing. ** ** aiCur[0] and aiCur[1] both get -1 if the where-clause logic is ** unable to use the ONEPASS optimization. */ int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){ memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace && pWInfo->eOnePass!=ONEPASS_OFF ){ sqlite3DebugPrintf("%s cursors: %d %d\n", pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI", aiCur[0], aiCur[1]); } #endif return pWInfo->eOnePass; } /* ** Move the content of pSrc into pDest */ static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){ |
︙ | ︙ | |||
178 179 180 181 182 183 184 | WhereClause *pWC; /* Shorthand for pScan->pWC */ WhereTerm *pTerm; /* The term being tested */ int k = pScan->k; /* Where to start scanning */ while( pScan->iEquiv<=pScan->nEquiv ){ iCur = pScan->aiCur[pScan->iEquiv-1]; iColumn = pScan->aiColumn[pScan->iEquiv-1]; | | | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | WhereClause *pWC; /* Shorthand for pScan->pWC */ WhereTerm *pTerm; /* The term being tested */ int k = pScan->k; /* Where to start scanning */ while( pScan->iEquiv<=pScan->nEquiv ){ iCur = pScan->aiCur[pScan->iEquiv-1]; iColumn = pScan->aiColumn[pScan->iEquiv-1]; if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0; while( (pWC = pScan->pWC)!=0 ){ for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn && (iColumn!=XN_EXPR || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0) && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquiv<ArraySize(pScan->aiCur) && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN ){ int j; |
︙ | ︙ | |||
277 278 279 280 281 282 283 | /* memset(pScan, 0, sizeof(*pScan)); */ pScan->pOrigWC = pWC; pScan->pWC = pWC; pScan->pIdxExpr = 0; if( pIdx ){ j = iColumn; iColumn = pIdx->aiColumn[j]; | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | /* memset(pScan, 0, sizeof(*pScan)); */ pScan->pOrigWC = pWC; pScan->pWC = pWC; pScan->pIdxExpr = 0; if( pIdx ){ j = iColumn; iColumn = pIdx->aiColumn[j]; if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; } if( pIdx && iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; pScan->zCollName = pIdx->azColl[j]; }else{ pScan->idxaff = 0; pScan->zCollName = 0; |
︙ | ︙ | |||
716 717 718 719 720 721 722 | for(i=BMS-1; i<pTable->nCol; i++){ pIdx->aiColumn[n] = i; pIdx->azColl[n] = "BINARY"; n++; } } assert( n==nKeyCol ); | | | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | for(i=BMS-1; i<pTable->nCol; i++){ pIdx->aiColumn[n] = i; pIdx->azColl[n] = "BINARY"; n++; } } assert( n==nKeyCol ); pIdx->aiColumn[n] = XN_ROWID; pIdx->azColl[n] = "BINARY"; /* Create the automatic index */ assert( pLevel->iIdxCur>=0 ); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); |
︙ | ︙ | |||
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 | #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** Return the affinity for a single column of an index. */ static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; } return pIdx->zColAff[iCol]; } #endif | > | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 | #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** Return the affinity for a single column of an index. */ static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ assert( iCol>=0 && iCol<pIdx->nColumn ); if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; } return pIdx->zColAff[iCol]; } #endif |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | ){ Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; sqlite3 *db = pParse->db; int nLower = -1; int nUpper = p->nSample+1; int rc = SQLITE_OK; | < | | 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 | ){ Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; sqlite3 *db = pParse->db; int nLower = -1; int nUpper = p->nSample+1; int rc = SQLITE_OK; u8 aff = sqlite3IndexColumnAffinity(db, p, nEq); CollSeq *pColl; sqlite3_value *p1 = 0; /* Value extracted from pLower */ sqlite3_value *p2 = 0; /* Value extracted from pUpper */ sqlite3_value *pVal = 0; /* Value extracted from record */ pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]); |
︙ | ︙ | |||
2231 2232 2233 2234 2235 2236 2237 | assert( nIn>0 ); /* RHS always has 2 or more terms... The parser ** changes "x IN (?)" into "x=?". */ }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); | > | > | 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 | assert( nIn>0 ); /* RHS always has 2 or more terms... The parser ** changes "x IN (?)" into "x=?". */ }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); if( iCol==XN_ROWID || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ if( iCol>=0 && pProbe->uniqNotNull==0 ){ pNew->wsFlags |= WHERE_UNQ_WANTED; }else{ pNew->wsFlags |= WHERE_ONEROW; } } }else if( eOp & WO_ISNULL ){ |
︙ | ︙ | |||
2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 | */ static int indexMightHelpWithOrderBy( WhereLoopBuilder *pBuilder, Index *pIndex, int iCursor ){ ExprList *pOB; int ii, jj; if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; ii<pOB->nExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); | > < | > > > > > > > | 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 | */ static int indexMightHelpWithOrderBy( WhereLoopBuilder *pBuilder, Index *pIndex, int iCursor ){ ExprList *pOB; ExprList *aColExpr; int ii, jj; if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; ii<pOB->nExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ return 1; } } } } return 0; } /* |
︙ | ︙ | |||
2576 2577 2578 2579 2580 2581 2582 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ | | | 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ ){ /* Generate auto-index WhereLoops */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){ |
︙ | ︙ | |||
2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 | if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr); pIdxInfo->idxStr = 0; pIdxInfo->idxNum = 0; pIdxInfo->needToFreeIdxStr = 0; pIdxInfo->orderByConsumed = 0; pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; rc = vtabBestIndex(pParse, pTab, pIdxInfo); if( rc ) goto whereLoopAddVtab_exit; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pNew->prereq = mExtra; mxTerm = -1; assert( pNew->nLSlot>=nConstraint ); for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0; | > | 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 | if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr); pIdxInfo->idxStr = 0; pIdxInfo->idxNum = 0; pIdxInfo->needToFreeIdxStr = 0; pIdxInfo->orderByConsumed = 0; pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; rc = vtabBestIndex(pParse, pTab, pIdxInfo); if( rc ) goto whereLoopAddVtab_exit; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pNew->prereq = mExtra; mxTerm = -1; assert( pNew->nLSlot>=nConstraint ); for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0; |
︙ | ︙ | |||
2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 | } /* A virtual table that is constrained by an IN clause may not ** consume the ORDER BY clause because (1) the order of IN terms ** is not necessarily related to the order of output terms and ** (2) Multiple outputs from a single IN value will not merge ** together. */ pIdxInfo->orderByConsumed = 0; } } } if( i>=nConstraint ){ pNew->nLTerm = mxTerm+1; assert( pNew->nLTerm<=pNew->nLSlot ); pNew->u.vtab.idxNum = pIdxInfo->idxNum; pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? pIdxInfo->nOrderBy : 0); pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); pNew->u.vtab.needFree = 0; } } } | > > > > > > > > > | 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 | } /* A virtual table that is constrained by an IN clause may not ** consume the ORDER BY clause because (1) the order of IN terms ** is not necessarily related to the order of output terms and ** (2) Multiple outputs from a single IN value will not merge ** together. */ pIdxInfo->orderByConsumed = 0; pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; } } } if( i>=nConstraint ){ pNew->nLTerm = mxTerm+1; assert( pNew->nLTerm<=pNew->nLSlot ); pNew->u.vtab.idxNum = pIdxInfo->idxNum; pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? pIdxInfo->nOrderBy : 0); pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated ** that the scan will visit at most one row. Clear it otherwise. */ if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){ pNew->wsFlags |= WHERE_ONEROW; }else{ pNew->wsFlags &= ~WHERE_ONEROW; } whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); pNew->u.vtab.needFree = 0; } } } |
︙ | ︙ | |||
3202 3203 3204 3205 3206 3207 3208 | nColumn = 1; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ nKeyCol = pIndex->nKeyCol; nColumn = pIndex->nColumn; assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); | | > | 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 | nColumn = 1; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ nKeyCol = pIndex->nKeyCol; nColumn = pIndex->nColumn; assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==XN_ROWID || !HasRowid(pIndex->pTable)); isOrderDistinct = IsUniqueIndex(pIndex); } /* Loop through all columns of the index and deal with the ones ** that are not constrained by == or IN. */ rev = revSet = 0; |
︙ | ︙ | |||
3234 3235 3236 3237 3238 3239 3240 | ** (revIdx) for the j-th column of the index. */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j]; if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; }else{ | | | 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 | ** (revIdx) for the j-th column of the index. */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j]; if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; }else{ iColumn = XN_ROWID; revIdx = 0; } /* An unconstrained column that might be NULL means that this ** WhereLoop is not well-ordered */ if( isOrderDistinct |
︙ | ︙ | |||
3260 3261 3262 3263 3264 3265 3266 | isMatch = 0; for(i=0; bOnce && i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; | > | | | > > > > > | 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 | isMatch = 0; for(i=0; bOnce && i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( iColumn>=(-1) ){ if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){ continue; } } if( iColumn>=0 ){ pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } isMatch = 1; break; |
︙ | ︙ | |||
4093 4094 4095 4096 4097 4098 4099 | /* Try to ORDER BY the result set to make distinct processing easier */ pWInfo->wctrlFlags |= WHERE_DISTINCTBY; pWInfo->pOrderBy = pResultSet; } } /* Construct the WhereLoop objects */ | | > | 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 | /* Try to ORDER BY the result set to make distinct processing easier */ pWInfo->wctrlFlags |= WHERE_DISTINCTBY; pWInfo->pOrderBy = pResultSet; } } /* Construct the WhereLoop objects */ WHERETRACE(0xffff,("*** Optimizer Start *** (wctrlFlags: 0x%x)\n", wctrlFlags)); #if defined(WHERETRACE_ENABLED) if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ int i; for(i=0; i<sWLB.pWC->nTerm; i++){ whereTermPrint(&sWLB.pWC->a[i], i); } } |
︙ | ︙ | |||
4512 4513 4514 4515 4516 4517 4518 | ** reference the index. */ if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ pIdx = pLoop->u.btree.pIndex; }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ pIdx = pLevel->u.pCovidx; } | > > | > > | 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 | ** reference the index. */ if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ pIdx = pLoop->u.btree.pIndex; }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ pIdx = pLevel->u.pCovidx; } if( pIdx && (pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable)) && !db->mallocFailed ){ last = sqlite3VdbeCurrentAddr(v); k = pLevel->addrBody; pOp = sqlite3VdbeGetOp(v, k); for(; k<last; k++, pOp++){ if( pOp->p1!=pLevel->iTabCur ) continue; if( pOp->opcode==OP_Column ){ int x = pOp->p2; assert( pIdx->pTable==pTab ); if( !HasRowid(pTab) ){ Index *pPk = sqlite3PrimaryKeyIndex(pTab); x = pPk->aiColumn[x]; assert( x>=0 ); } x = sqlite3ColumnOfIndex(pIdx, x); if( x>=0 ){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; } assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 ); |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | } /* ** Return the name of the i-th column of the pIdx index. */ static const char *explainIndexColumnName(Index *pIdx, int i){ i = pIdx->aiColumn[i]; | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | } /* ** Return the name of the i-th column of the pIdx index. */ static const char *explainIndexColumnName(Index *pIdx, int i){ i = pIdx->aiColumn[i]; if( i==XN_EXPR ) return "<expr>"; if( i==XN_ROWID ) return "rowid"; return pIdx->pTable->aCol[i].zName; } /* ** Argument pLevel describes a strategy for scanning table pTab. This ** function appends text to pStr that describes the subset of table ** rows scanned by the strategy in the form of an SQL expression. |
︙ | ︙ | |||
510 511 512 513 514 515 516 | pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), iIdxCur, 0, regBase, nSkip); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); sqlite3VdbeJumpHere(v, j); for(j=0; j<nSkip; j++){ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j); | | | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), iIdxCur, 0, regBase, nSkip); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); sqlite3VdbeJumpHere(v, j); for(j=0; j<nSkip; j++){ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j); testcase( pIdx->aiColumn[j]==XN_EXPR ); VdbeComment((v, "%s", explainIndexColumnName(pIdx, j))); } } /* Evaluate the equality constraints */ assert( zAff==0 || (int)strlen(zAff)>=nEq ); |
︙ | ︙ | |||
696 697 698 699 700 701 702 | VdbeCoverage(v); pLoop->u.vtab.needFree = 0; for(j=0; j<nConstraint && j<16; j++){ if( (pLoop->u.vtab.omitMask>>j)&1 ){ disableTerm(pLevel, pLoop->aLTerm[j]); } } | < > | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | VdbeCoverage(v); pLoop->u.vtab.needFree = 0; for(j=0; j<nConstraint && j<16; j++){ if( (pLoop->u.vtab.omitMask>>j)&1 ){ disableTerm(pLevel, pLoop->aLTerm[j]); } } pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); sqlite3ExprCachePop(pParse); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ if( (pLoop->wsFlags & WHERE_IPK)!=0 |
︙ | ︙ |
Changes to src/whereexpr.c.
︙ | ︙ | |||
946 947 948 949 950 951 952 | eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } exprCommute(pParse, pDup); | < | 946 947 948 949 950 951 952 953 954 955 956 957 958 959 | eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } exprCommute(pParse, pDup); pNew->leftCursor = iCur; pNew->u.leftColumn = iColumn; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; } |
︙ | ︙ |
Changes to test/delete4.test.
︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 | do_execsql_test 3.3 { SELECT i FROM t1 ORDER BY i; } {1 3 5 7} do_execsql_test 3.4 { PRAGMA integrity_check; } {ok} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 3.3 { SELECT i FROM t1 ORDER BY i; } {1 3 5 7} do_execsql_test 3.4 { PRAGMA integrity_check; } {ok} # Between 2015-09-14 and 2015-09-28, the following test cases would result # in corruption (wrong # of entries in index) due to a bug in the ONEPASS # optimization. # do_execsql_test 4.1 { DROP TABLE IF EXISTS t4; CREATE TABLE t4(col0, col1); INSERT INTO "t4" VALUES(14, 'abcde'); CREATE INDEX idx_t4_0 ON t4 (col1, col0); CREATE INDEX idx_t4_3 ON t4 (col0); DELETE FROM t4 WHERE col0=69 OR col0>7; PRAGMA integrity_check; } {ok} do_execsql_test 4.2 { DROP TABLE IF EXISTS t4; CREATE TABLE t4(col0, col1); INSERT INTO "t4" VALUES(14, 'abcde'); CREATE INDEX idx_t4_3 ON t4 (col0); CREATE INDEX idx_t4_0 ON t4 (col1, col0); DELETE FROM t4 WHERE col0=69 OR col0>7; PRAGMA integrity_check; } {ok} do_execsql_test 4.11 { DROP TABLE IF EXISTS t4; CREATE TABLE t4(col0, col1, pk PRIMARY KEY) WITHOUT ROWID; INSERT INTO t4 VALUES(14, 'abcde','xyzzy'); CREATE INDEX idx_t4_0 ON t4 (col1, col0); CREATE INDEX idx_t4_3 ON t4 (col0); DELETE FROM t4 WHERE col0=69 OR col0>7; PRAGMA integrity_check; } {ok} do_execsql_test 4.12 { DROP TABLE IF EXISTS t4; CREATE TABLE t4(col0, col1, pk PRIMARY KEY) WITHOUT ROWID; INSERT INTO t4 VALUES(14, 'abcde','xyzzy'); CREATE INDEX idx_t4_3 ON t4 (col0); CREATE INDEX idx_t4_0 ON t4 (col1, col0); DELETE FROM t4 WHERE col0=69 OR col0>7; PRAGMA integrity_check; } {ok} finish_test |
Changes to test/fkey1.test.
︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 | SELECT 1, """5" FROM """4"; DELETE FROM """1"; SELECT 2, """5" FROM """4"; } {1 abc} do_execsql_test fkey1-4.2 { PRAGMA table_info="""1"; } {0 {"2} TEXT 0 {} 1 1 {"3} TEXT 0 {} 0} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT 1, """5" FROM """4"; DELETE FROM """1"; SELECT 2, """5" FROM """4"; } {1 abc} do_execsql_test fkey1-4.2 { PRAGMA table_info="""1"; } {0 {"2} TEXT 0 {} 1 1 {"3} TEXT 0 {} 0} #------------------------------------------------------------------------- # do_execsql_test fkey1-5.1 { CREATE TABLE t11( x INTEGER PRIMARY KEY, parent REFERENCES t11 ON DELETE CASCADE ); INSERT INTO t11 VALUES (1, NULL), (2, 1), (3, 2); } {} # The REPLACE part of this statement deletes the row (2, 1). Then the # DELETE CASCADE caused by deleting that row removes the (3, 2) row. Which # would have been the parent of the new row being inserted. Causing an # FK violation. # do_catchsql_test fkey1-5.2 { INSERT OR REPLACE INTO t11 VALUES (2, 3); } {1 {FOREIGN KEY constraint failed}} # 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 ); INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (1, null, 'A'); INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 1, 'A-2-1'); INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (3, 2, 'A-3-2'); INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (4, 3, 'A-4-3'); } do_catchsql_test fkey1-5.4 { INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 3, 'A-2-3'); } {1 {FOREIGN KEY constraint failed}} finish_test |
Changes to test/fts3conf.test.
︙ | ︙ | |||
82 83 84 85 86 87 88 | 6 "INSERT OR ROLLBACK $T2" 1 1 {{a b c d} {e f g h}} 7 "INSERT OR ABORT $T2" 1 1 {{a b c d} {e f g h} {i j k l}} 8 "INSERT OR FAIL $T2" 1 1 {{a b c d} {e f g h} {i j k l} z} 9 "INSERT OR IGNORE $T2" 1 0 {{a b c d} {e f g h} {i j k l} z} 10 "INSERT OR REPLACE $T2" 1 0 {{a b c d} y {i j k l} z} | | | | | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 6 "INSERT OR ROLLBACK $T2" 1 1 {{a b c d} {e f g h}} 7 "INSERT OR ABORT $T2" 1 1 {{a b c d} {e f g h} {i j k l}} 8 "INSERT OR FAIL $T2" 1 1 {{a b c d} {e f g h} {i j k l} z} 9 "INSERT OR IGNORE $T2" 1 0 {{a b c d} {e f g h} {i j k l} z} 10 "INSERT OR REPLACE $T2" 1 0 {{a b c d} y {i j k l} z} 11 "UPDATE OR ROLLBACK $T3" 0 1 {{a b c d} {e f g h}} 12 "UPDATE OR ABORT $T3" 0 1 {{a b c d} {e f g h} {i j k l}} 13 "UPDATE OR FAIL $T3" 0 1 {{a b c d} {e f g h} {i j k l}} 14 "UPDATE OR IGNORE $T3" 0 0 {{a b c d} {e f g h} {i j k l}} 15 "UPDATE OR REPLACE $T3" 0 0 {{a b c d} {i j k l}} 16 "UPDATE OR ROLLBACK $T4" 1 1 {{a b c d} {e f g h}} 17 "UPDATE OR ABORT $T4" 1 1 {{a b c d} {e f g h} {i j k l}} 18 "UPDATE OR FAIL $T4" 1 1 {{e f g h} {i j k l} {a b c d}} 19 "UPDATE OR IGNORE $T4" 1 0 {{e f g h} {i j k l} {a b c d}} 20 "UPDATE OR REPLACE $T4" 1 0 {{e f g h} {a b c d}} }] { |
︙ | ︙ | |||
173 174 175 176 177 178 179 180 181 | SELECT docid FROM t3; } {3 4 5} do_execsql_test 3.8 { UPDATE OR REPLACE t3 SET docid = 5, content='three four' WHERE docid = 4; SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one' } {X'0200000002000000'} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT docid FROM t3; } {3 4 5} do_execsql_test 3.8 { UPDATE OR REPLACE t3 SET docid = 5, content='three four' WHERE docid = 4; SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one' } {X'0200000002000000'} #------------------------------------------------------------------------- # Test that the xSavepoint is invoked correctly if the first write # operation within a transaction is to a virtual table. # do_catchsql_test 4.1.1 { CREATE VIRTUAL TABLE t0 USING fts4; BEGIN; INSERT INTO t0(rowid, content) SELECT 1, 'abc' UNION ALL SELECT 2, 'def' UNION ALL SELECT 1, 'ghi'; } {1 {constraint failed}} do_execsql_test 4.1.2 { COMMIT; } do_execsql_test 4.1.3 { SELECT * FROM t0 WHERE t0 MATCH 'abc'; INSERT INTO t0(t0) VALUES('integrity-check'); } {} do_execsql_test 4.2.1 { CREATE VIRTUAL TABLE t01 USING fts4; BEGIN; SAVEPOINT abc; INSERT INTO t01 VALUES('a b c'); ROLLBACK TO abc; COMMIT; } do_execsql_test 4.2.2 { SELECT * FROM t01 WHERE t01 MATCH 'b'; INSERT INTO t01(t01) VALUES('integrity-check'); } {} finish_test |
Changes to test/fts3expr3.test.
︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 | proc balanced_andor_tree {nEntry} { set tree [balanced_exprtree_structure $nEntry] set node "{[balanced_and_tree $nEntry]}" regsub -all AND $node OR node regsub -all xxx $tree $node tree return $tree } # Test that queries like "1 AND 2 AND 3 AND 4..." are transformed to # balanced trees by FTS. # for {set i 1} {$i < 100} {incr i} { do_test 1.$i { test_fts3expr2 [random_and_query $i] | > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | proc balanced_andor_tree {nEntry} { set tree [balanced_exprtree_structure $nEntry] set node "{[balanced_and_tree $nEntry]}" regsub -all AND $node OR node regsub -all xxx $tree $node tree return $tree } if 1 { # Test that queries like "1 AND 2 AND 3 AND 4..." are transformed to # balanced trees by FTS. # for {set i 1} {$i < 100} {incr i} { do_test 1.$i { test_fts3expr2 [random_and_query $i] |
︙ | ︙ | |||
197 198 199 200 201 202 203 204 205 206 | set query [random_andor_query 12] set result [balanced_andor_tree 12] do_faultsim_test fts3expr3-fault-1 -faults oom-* -body { test_fts3expr2 $::query } -test { faultsim_test_result [list 0 $::result] } set sqlite_fts3_enable_parentheses 0 finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | set query [random_andor_query 12] set result [balanced_andor_tree 12] do_faultsim_test fts3expr3-fault-1 -faults oom-* -body { test_fts3expr2 $::query } -test { faultsim_test_result [list 0 $::result] } } #------------------------------------------------------------------- foreach {tn expr res} { 1 {1 OR 2 OR 3 OR 4} {OR {OR {P 1} {P 2}} {OR {P 3} {P 4}}} 2 {1 OR (2 AND 3 AND 4 AND 5)} {OR {P 1} {AND {AND {P 2} {P 3}} {AND {P 4} {P 5}}}} 3 {(2 AND 3 AND 4 AND 5) OR 1} {OR {AND {AND {P 2} {P 3}} {AND {P 4} {P 5}}} {P 1}} 4 {1 AND (2 OR 3 OR 4 OR 5)} {AND {P 1} {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}}} 5 {(2 OR 3 OR 4 OR 5) AND 1} {AND {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}} {P 1}} 6 {(2 OR 3 OR 4 OR 5) NOT 1} {NOT {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}} {P 1}} 7 {1 NOT (2 OR 3 OR 4 OR 5)} {NOT {P 1} {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}}} 8 {(1 OR 2 OR 3 OR 4) NOT (5 AND 6 AND 7 AND 8)} {NOT {OR {OR {P 1} {P 2}} {OR {P 3} {P 4}}} {AND {AND {P 5} {P 6}} {AND {P 7} {P 8}}}} } { do_test 5.1.$tn { test_fts3expr2 $expr } $res } set sqlite_fts3_enable_parentheses 0 finish_test |
Added test/fts4onepass.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 | # 2015 Sep 27 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set ::testprefix fts4onepass # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE ft USING fts3; INSERT INTO ft(rowid, content) VALUES(1, '1 2 3'); INSERT INTO ft(rowid, content) VALUES(2, '4 5 6'); INSERT INTO ft(rowid, content) VALUES(3, '7 8 9'); } #------------------------------------------------------------------------- # Check that UPDATE and DELETE statements that feature "WHERE rowid=?" or # or "WHERE docid=?" clauses do not use statement journals. But that other # DELETE and UPDATE statements do. # # Note: "MATCH ? AND docid=?" does use a statement journal. # foreach {tn sql uses} { 1.1 { DELETE FROM ft } 1 1.2 { DELETE FROM ft WHERE docid=? } 0 1.3 { DELETE FROM ft WHERE rowid=? } 0 1.4 { DELETE FROM ft WHERE ft MATCH '1' } 1 1.5 { DELETE FROM ft WHERE ft MATCH '1' AND docid=? } 1 1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1 2.1 { UPDATE ft SET content='a b c' } 1 2.2 { UPDATE ft SET content='a b c' WHERE docid=? } 0 2.3 { UPDATE ft SET content='a b c' WHERE rowid=? } 0 2.4 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' } 1 2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND docid=? } 1 2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1 } { do_test 1.$tn { sql_uses_stmt db $sql } $uses } #------------------------------------------------------------------------- # Check that putting a "DELETE/UPDATE ... WHERE rowid=?" statement in a # trigger program does not prevent the VM from using a statement # transaction. Even if the calling statement cannot hit a constraint. # do_execsql_test 2.0 { CREATE TABLE t1(x); CREATE TRIGGER t1_ai AFTER INSERT ON t1 BEGIN DELETE FROM ft WHERE rowid=new.x; END; CREATE TRIGGER t1_ad AFTER DELETE ON t1 BEGIN UPDATE ft SET content = 'a b c' WHERE rowid=old.x; END; CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 BEGIN DELETE FROM ft WHERE rowid=old.x; END; } foreach {tn sql uses} { 1 { INSERT INTO t1 VALUES(1) } 1 2 { DELETE FROM t1 WHERE x=4 } 1 3 { UPDATE t1 SET x=10 WHERE x=11 } 1 } { do_test 2.$tn { sql_uses_stmt db $sql } $uses } #------------------------------------------------------------------------- # Test that an "UPDATE ... WHERE rowid=?" works and does not corrupt the # index when it strikes a constraint. Both inside and outside a # transaction. # foreach {tn tcl1 tcl2} { 1 {} {} 2 { execsql BEGIN } { if {[sqlite3_get_autocommit db]==1} { error "transaction rolled back!" } execsql COMMIT } } { do_execsql_test 3.$tn.0 { DROP TABLE IF EXISTS ft2; CREATE VIRTUAL TABLE ft2 USING fts4; INSERT INTO ft2(rowid, content) VALUES(1, 'a b c'); INSERT INTO ft2(rowid, content) VALUES(2, 'a b d'); INSERT INTO ft2(rowid, content) VALUES(3, 'a b e'); } eval $tcl1 foreach {tn2 sql content} { 1 { UPDATE ft2 SET docid=2 WHERE docid=1 } { 1 {a b c} 2 {a b d} 3 {a b e} } 2 { INSERT INTO ft2(rowid, content) VALUES(4, 'a b f'); UPDATE ft2 SET docid=5 WHERE docid=4; UPDATE ft2 SET docid=3 WHERE docid=5; } { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } 3 { UPDATE ft2 SET docid=3 WHERE docid=4; -- matches 0 rows UPDATE ft2 SET docid=2 WHERE docid=3; } { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } 4 { INSERT INTO ft2(rowid, content) VALUES(4, 'a b g'); UPDATE ft2 SET docid=-1 WHERE docid=4; UPDATE ft2 SET docid=3 WHERE docid=-1; } {-1 {a b g} 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } 5 { DELETE FROM ft2 WHERE rowid=451; DELETE FROM ft2 WHERE rowid=-1; UPDATE ft2 SET docid = 2 WHERE docid = 1; } {1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } } { do_catchsql_test 3.$tn.$tn2.a $sql {1 {constraint failed}} do_execsql_test 3.$tn.$tn2.b { SELECT rowid, content FROM ft2 } $content do_execsql_test 3.$tn.$tn2.c { INSERT INTO ft2(ft2) VALUES('integrity-check'); } } eval $tcl2 } finish_test |
Changes to test/fuzzdata3.db.
cannot compute difference between binary files
Changes to test/indexexpr1.test.
︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 | } {1 1 1} do_execsql_test indexexpr1-160eqp { EXPLAIN QUERY PLAN SELECT rowid, b, c FROM t1 WHERE substr(a,27,3)=='ord' AND d>=29; } {/USING INDEX t1a2/} do_execsql_test indexexpr1-200 { DROP TABLE t1; CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID; INSERT INTO t1(id,a,b,c) VALUES(1,'In_the_beginning_was_the_Word',1,1), (2,'and_the_Word_was_with_God',1,2), | > > > > > > > > > > > > > > > > > | 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 | } {1 1 1} do_execsql_test indexexpr1-160eqp { EXPLAIN QUERY PLAN SELECT rowid, b, c FROM t1 WHERE substr(a,27,3)=='ord' AND d>=29; } {/USING INDEX t1a2/} # ORDER BY using an indexed expression # do_execsql_test indexexpr1-170 { CREATE INDEX t1alen ON t1(length(a)); SELECT length(a) FROM t1 ORDER BY length(a); } {20 25 27 29 38 52} do_execsql_test indexexpr1-170eqp { EXPLAIN QUERY PLAN SELECT length(a) FROM t1 ORDER BY length(a); } {/SCAN TABLE t1 USING INDEX t1alen/} do_execsql_test indexexpr1-171 { SELECT length(a) FROM t1 ORDER BY length(a) DESC; } {52 38 29 27 25 20} do_execsql_test indexexpr1-171eqp { EXPLAIN QUERY PLAN SELECT length(a) FROM t1 ORDER BY length(a) DESC; } {/SCAN TABLE t1 USING INDEX t1alen/} do_execsql_test indexexpr1-200 { DROP TABLE t1; CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID; INSERT INTO t1(id,a,b,c) VALUES(1,'In_the_beginning_was_the_Word',1,1), (2,'and_the_Word_was_with_God',1,2), |
︙ | ︙ | |||
189 190 191 192 193 194 195 | do_execsql_test indexexpr1-400 { CREATE TABLE t3(a,b,c); WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<30) INSERT INTO t3(a,b,c) SELECT x, printf('ab%04xyz',x), random() FROM c; CREATE UNIQUE INDEX t3abc ON t3(CAST(a AS text), b, substr(c,1,3)); SELECT a FROM t3 WHERE CAST(a AS text)<='10' ORDER BY +a; | > | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | do_execsql_test indexexpr1-400 { CREATE TABLE t3(a,b,c); WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<30) INSERT INTO t3(a,b,c) SELECT x, printf('ab%04xyz',x), random() FROM c; CREATE UNIQUE INDEX t3abc ON t3(CAST(a AS text), b, substr(c,1,3)); SELECT a FROM t3 WHERE CAST(a AS text)<='10' ORDER BY +a; PRAGMA integrity_check; } {1 10 ok} do_catchsql_test indexexpr1-410 { INSERT INTO t3 SELECT * FROM t3 WHERE rowid=10; } {1 {UNIQUE constraint failed: index 't3abc'}} do_execsql_test indexexpr1-500 { CREATE TABLE t5(a); CREATE TABLE cnt(x); |
︙ | ︙ | |||
250 251 252 253 254 255 256 257 258 | CREATE INDEX t72yz ON t72(y+z); INSERT INTO t71(a,b,c) VALUES(1,11,2),(2,7,15),(3,5,4); INSERT INTO t72(x,y,z) VALUES(1,10,3),(2,8,14),(3,9,9); SELECT a, x, '|' FROM t71, t72 WHERE b+c=y+z ORDER BY +a, +x; } {1 1 | 2 2 |} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE INDEX t72yz ON t72(y+z); INSERT INTO t71(a,b,c) VALUES(1,11,2),(2,7,15),(3,5,4); INSERT INTO t72(x,y,z) VALUES(1,10,3),(2,8,14),(3,9,9); SELECT a, x, '|' FROM t71, t72 WHERE b+c=y+z ORDER BY +a, +x; } {1 1 | 2 2 |} # Collating sequences on indexes of expressions # do_execsql_test indexexpr1-800 { DROP TABLE IF EXISTS t8; CREATE TABLE t8(a INTEGER PRIMARY KEY, b TEXT); CREATE UNIQUE INDEX t8bx ON t8(substr(b,2,4) COLLATE nocase); INSERT INTO t8(a,b) VALUES(1,'Alice'),(2,'Bartholemew'),(3,'Cynthia'); SELECT * FROM t8 WHERE substr(b,2,4)='ARTH' COLLATE nocase; } {2 Bartholemew} do_catchsql_test indexexpr1-810 { INSERT INTO t8(a,b) VALUES(4,'BARTHMERE'); } {1 {UNIQUE constraint failed: index 't8bx'}} do_catchsql_test indexexpr1-820 { DROP INDEX t8bx; CREATE UNIQUE INDEX t8bx ON t8(substr(b,2,4) COLLATE rtrim); INSERT INTO t8(a,b) VALUES(4,'BARTHMERE'); } {0 {}} # Check that PRAGMA integrity_check works correctly on a # UNIQUE index that includes rowid and expression terms. # do_execsql_test indexexpr1-900 { CREATE TABLE t9(a,b,c,d); CREATE UNIQUE INDEX t9x1 ON t9(c,abs(d),b); INSERT INTO t9(rowid,a,b,c,d) VALUES(1,2,3,4,5); INSERT INTO t9(rowid,a,b,c,d) VALUES(2,NULL,NULL,NULL,NULL); INSERT INTO t9(rowid,a,b,c,d) VALUES(3,NULL,NULL,NULL,NULL); INSERT INTO t9(rowid,a,b,c,d) VALUES(4,5,6,7,8); PRAGMA integrity_check; } {ok} do_catchsql_test indexexpr1-910 { INSERT INTO t9(a,b,c,d) VALUES(5,6,7,-8); } {1 {UNIQUE constraint failed: index 't9x1'}} finish_test |
Changes to test/json101.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # This file implements tests for JSON SQL functions extension to the # SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl | > > > > | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # This file implements tests for JSON SQL functions extension to the # SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !json1 { finish_test return } do_execsql_test json101-1.1.00 { SELECT json_array(1,2.5,null,'hello'); } {[1,2.5,null,"hello"]} do_execsql_test json101-1.1.01 { SELECT json_array(1,'{"abc":2.5,"def":null,"ghi":hello}',99); -- the second term goes in as a string: } {[1,"{\\"abc\\":2.5,\\"def\\":null,\\"ghi\\":hello}",99]} |
︙ | ︙ |
Changes to test/json102.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # This file contains tests automatically generated from the json1 # documentation. # set testdir [file dirname $argv0] source $testdir/tester.tcl | > > > > | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # This file contains tests automatically generated from the json1 # documentation. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !json1 { finish_test return } do_execsql_test json102-100 { SELECT json_object('ex','[52,3.14159]'); } {{{"ex":"[52,3.14159]"}}} do_execsql_test json102-110 { SELECT json_object('ex',json('[52,3.14159]')); } {{{"ex":[52,3.14159]}}} do_execsql_test json102-120 { |
︙ | ︙ |
Added test/offset1.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 | # 2015-10-06 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements test cases for the [b65cb2c8d91f6685841d7d1e13b6] # bug: Correct handling of LIMIT and OFFSET on a UNION ALL query where # the right-hand SELECT contains an ORDER BY in a subquery. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !compound { finish_test return } do_execsql_test offset1-1.1 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'); CREATE TABLE t2(x,y); INSERT INTO t2 VALUES(8,'y'),(9,'z'),(6,'w'),(7,'x'); SELECT count(*) FROM t1, t2; } {20} do_execsql_test offset1-1.2.0 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 0; } {1 a 2 b 3 c} do_execsql_test offset1-1.2.1 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 1; } {2 b 3 c 4 d} do_execsql_test offset1-1.2.2 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 2; } {3 c 4 d 5 e} do_execsql_test offset1-1.2.3 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 3; } {4 d 5 e 6 w} do_execsql_test offset1-1.2.4 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 4; } {5 e 6 w 7 x} do_execsql_test offset1-1.2.5 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 5; } {6 w 7 x 8 y} do_execsql_test offset1-1.2.6 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 6; } {7 x 8 y 9 z} do_execsql_test offset1-1.2.7 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 7; } {8 y 9 z} do_execsql_test offset1-1.2.8 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 8; } {9 z} do_execsql_test offset1-1.2.9 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 9; } {} do_execsql_test offset1-1.3.0 { SELECT * FROM t1 LIMIT 0; } {} do_execsql_test offset1-1.4.0 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 0 OFFSET 1; } {} do_execsql_test offset1-1.4.1 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 1 OFFSET 1; } {2 b} do_execsql_test offset1-1.4.2 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 2 OFFSET 1; } {2 b 3 c} do_execsql_test offset1-1.4.3 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 3 OFFSET 1; } {2 b 3 c 4 d} do_execsql_test offset1-1.4.4 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 4 OFFSET 1; } {2 b 3 c 4 d 5 e} do_execsql_test offset1-1.4.5 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 5 OFFSET 1; } {2 b 3 c 4 d 5 e 6 w} do_execsql_test offset1-1.4.6 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 6 OFFSET 1; } {2 b 3 c 4 d 5 e 6 w 7 x} do_execsql_test offset1-1.4.7 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 7 OFFSET 1; } {2 b 3 c 4 d 5 e 6 w 7 x 8 y} do_execsql_test offset1-1.4.8 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 8 OFFSET 1; } {2 b 3 c 4 d 5 e 6 w 7 x 8 y 9 z} do_execsql_test offset1-1.4.9 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 9 OFFSET 1; } {2 b 3 c 4 d 5 e 6 w 7 x 8 y 9 z} finish_test |
Changes to test/releasetest.tcl.
︙ | ︙ | |||
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 | -DSQLITE_SOUNDEX=1 } "Update-Delete-Limit" { -O2 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_ENABLE_STMT_SCANSTATUS } "Check-Symbols" { -DSQLITE_MEMDEBUG=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_MEMSYS5=1 -DSQLITE_ENABLE_MEMSYS3=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_STMT_SCANSTATUS } "Debug-One" { --disable-shared -O2 -DSQLITE_DEBUG=1 -DSQLITE_MEMDEBUG=1 -DSQLITE_MUTEX_NOOP=1 | > > | 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 | -DSQLITE_SOUNDEX=1 } "Update-Delete-Limit" { -O2 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_ENABLE_STMT_SCANSTATUS --enable-json1 } "Check-Symbols" { -DSQLITE_MEMDEBUG=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_MEMSYS5=1 -DSQLITE_ENABLE_MEMSYS3=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_STMT_SCANSTATUS --enable-json1 --enable-fts5 } "Debug-One" { --disable-shared -O2 -DSQLITE_DEBUG=1 -DSQLITE_MEMDEBUG=1 -DSQLITE_MUTEX_NOOP=1 |
︙ | ︙ | |||
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 | -DSQLITE_ENABLE_IOTRACE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_MAX_PAGE_SIZE=4096 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_OMIT_VIRTUALTABLE=1 -DSQLITE_TEMP_STORE=3 } "Device-Two" { -DSQLITE_4_BYTE_ALIGNED_MALLOC=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_DEFAULT_LOCKING_MODE=0 -DSQLITE_DEFAULT_PAGE_SIZE=1024 -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000 -DSQLITE_DISABLE_LFS=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_MAX_COMPOUND_SELECT=50 -DSQLITE_MAX_PAGE_SIZE=32768 -DSQLITE_OMIT_TRACE=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_THREADSAFE=2 } "Locking-Style" { -O2 -DSQLITE_ENABLE_LOCKING_STYLE=1 } "OS-X" { -O1 # Avoid a compiler bug in gcc 4.2.1 build 5658 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_THREADSAFE=2 -DSQLITE_OS_UNIX=1 -DSQLITE_ENABLE_LOCKING_STYLE=1 -DUSE_PREAD=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_MAX_LENGTH=2147483645 -DSQLITE_MAX_VARIABLE_NUMBER=500000 -DSQLITE_DEBUG=1 -DSQLITE_PREFER_PROXY_LOCKING=1 -DSQLITE_ENABLE_API_ARMOR=1 } "Extra-Robustness" { -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_MAX_ATTACHED=62 } "Devkit" { -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_MAX_ATTACHED=30 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_PARENTHESIS -DSQLITE_DISABLE_FTS4_DEFERRED -DSQLITE_ENABLE_RTREE } "No-lookaside" { -DSQLITE_TEST_REALLOC_STRESS=1 -DSQLITE_OMIT_LOOKASIDE=1 -DHAVE_USLEEP=1 } "Valgrind" { -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE } # The next group of configurations are used only by the # Failure-Detection platform. They are all the same, but we need # different names for them all so that they results appear in separate # subdirectories. # | > > > > > > | 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 | -DSQLITE_ENABLE_IOTRACE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_MAX_PAGE_SIZE=4096 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_OMIT_VIRTUALTABLE=1 -DSQLITE_TEMP_STORE=3 --enable-json1 } "Device-Two" { -DSQLITE_4_BYTE_ALIGNED_MALLOC=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_DEFAULT_LOCKING_MODE=0 -DSQLITE_DEFAULT_PAGE_SIZE=1024 -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000 -DSQLITE_DISABLE_LFS=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_MAX_COMPOUND_SELECT=50 -DSQLITE_MAX_PAGE_SIZE=32768 -DSQLITE_OMIT_TRACE=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_THREADSAFE=2 --enable-json1 --enable-fts5 } "Locking-Style" { -O2 -DSQLITE_ENABLE_LOCKING_STYLE=1 } "OS-X" { -O1 # Avoid a compiler bug in gcc 4.2.1 build 5658 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_THREADSAFE=2 -DSQLITE_OS_UNIX=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_LOCKING_STYLE=1 -DUSE_PREAD=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_MAX_LENGTH=2147483645 -DSQLITE_MAX_VARIABLE_NUMBER=500000 -DSQLITE_DEBUG=1 -DSQLITE_PREFER_PROXY_LOCKING=1 -DSQLITE_ENABLE_API_ARMOR=1 --enable-json1 --enable-fts5 } "Extra-Robustness" { -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_MAX_ATTACHED=62 } "Devkit" { -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_MAX_ATTACHED=30 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_PARENTHESIS -DSQLITE_DISABLE_FTS4_DEFERRED -DSQLITE_ENABLE_RTREE --enable-json1 --enable-fts5 } "No-lookaside" { -DSQLITE_TEST_REALLOC_STRESS=1 -DSQLITE_OMIT_LOOKASIDE=1 -DHAVE_USLEEP=1 } "Valgrind" { -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE --enable-json1 } # The next group of configurations are used only by the # Failure-Detection platform. They are all the same, but we need # different names for them all so that they results appear in separate # subdirectories. # |
︙ | ︙ |
Changes to test/spellfix2.test.
︙ | ︙ | |||
72 73 74 75 76 77 78 | WHERE word MATCH 'amstedam*' AND distance <= 100 AND top=20; } { 32 20 } do_execsql_test 1.6 { SELECT word, distance, matchlen FROM demo | | > | | | | | < | | | | | | | < | | > > | > | | | | | | | | | | | 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 | WHERE word MATCH 'amstedam*' AND distance <= 100 AND top=20; } { 32 20 } do_execsql_test 1.6 { SELECT word, distance, matchlen FROM demo WHERE word MATCH 'amstedam*' AND distance <= 100 ORDER BY distance, word; } { amsterdam 100 9 amsterdama 100 9 amsterdamania 100 9 amsterdamb 100 9 amsterdamc 100 9 amsterdamd 100 9 amsterdame 100 9 amsterdamf 100 9 amsterdamg 100 9 amsterdamh 100 9 amsterdami 100 9 amsterdamj 100 9 amsterdamk 100 9 amsterdaml 100 9 amsterdamlaan 100 9 amsterdamm 100 9 amsterdammetje 100 9 amsterdamn 100 9 amsterdamo 100 9 amsterdamp 100 9 amsterdamq 100 9 amsterdamr 100 9 amsterdams 100 9 amsterdamsestraat 100 9 amsterdamt 100 9 amsterdamu 100 9 amsterdamv 100 9 amsterdamw 100 9 amsterdamweg 100 9 amsterdamx 100 9 amsterdamy 100 9 amsterdamz 100 9 } do_execsql_test 1.7 { SELECT word, distance, matchlen FROM demo WHERE word MATCH 'amstedam*' AND distance <= 100 AND top=20 ORDER BY distance, word; } { amsterdam 100 9 amsterdama 100 9 amsterdamania 100 9 amsterdamb 100 9 amsterdamc 100 9 amsterdame 100 9 amsterdamf 100 9 amsterdamg 100 9 amsterdamh 100 9 amsterdami 100 9 amsterdamm 100 9 amsterdammetje 100 9 amsterdamn 100 9 amsterdamo 100 9 amsterdamp 100 9 amsterdamu 100 9 amsterdamv 100 9 amsterdamw 100 9 amsterdamweg 100 9 amsterdamy 100 9 } finish_test |
Changes to test/uri.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 71 72 | # # NOTE: Due to limits on legal characters for file names imposed by # Windows, we must skip the final two tests here (i.e. the # question mark is illegal in a file name on Windows). # if {$tn>14} break # # NOTE: On Windows, we need to account for the fact that the current # directory does not start with a forward slash. # set uri [string map [list PWD/ /[test_pwd /]] $uri] } else { set uri [string map [list PWD/ [test_pwd /]] $uri] | > > > > > > > > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | # # NOTE: Due to limits on legal characters for file names imposed by # Windows, we must skip the final two tests here (i.e. the # question mark is illegal in a file name on Windows). # if {$tn>14} break # # NOTE: When running on Tcl 8.6 (or higher?) on Windows, a colon within # the file name no longer tries to access an alternate data stream # (ADS) named "test.db" for the "http" file, causing some spurious # failures of this test. # if {$tn==12 && $::tcl_version>=8.6} continue # # NOTE: On Windows, we need to account for the fact that the current # directory does not start with a forward slash. # set uri [string map [list PWD/ /[test_pwd /]] $uri] } else { set uri [string map [list PWD/ [test_pwd /]] $uri] |
︙ | ︙ |
Changes to test/view.test.
︙ | ︙ | |||
157 158 159 160 161 162 163 164 165 166 167 168 169 170 | CREATE VIEW v1c(x,y,z) AS SELECT a, b+c, c-b FROM t1; SELECT * FROM v1c LIMIT 1; } } {x 2 y 7 z 1} do_catchsql_test view-3.3.4 { CREATE VIEW v1err(x,y DESC,z) AS SELECT a, b+c, c-b FROM t1; } {1 {syntax error after column name "y"}} ifcapable compound { do_test view-3.4 { execsql2 { CREATE VIEW v3 AS SELECT a FROM t1 UNION SELECT b FROM t1 ORDER BY b; SELECT * FROM v3 LIMIT 4; } | > > > > > > > > > > | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | CREATE VIEW v1c(x,y,z) AS SELECT a, b+c, c-b FROM t1; SELECT * FROM v1c LIMIT 1; } } {x 2 y 7 z 1} do_catchsql_test view-3.3.4 { CREATE VIEW v1err(x,y DESC,z) AS SELECT a, b+c, c-b FROM t1; } {1 {syntax error after column name "y"}} do_catchsql_test view-3.3.5 { DROP VIEW IF EXISTS v1err; CREATE VIEW v1err(x,y) AS SELECT a, b+c, c-b FROM t1; SELECT * FROM v1err; } {1 {expected 2 columns for 'v1err' but got 3}} do_catchsql_test view-3.3.6 { DROP VIEW IF EXISTS v1err; CREATE VIEW v1err(w,x,y,z) AS SELECT a, b+c, c-b FROM t1; SELECT * FROM v1err; } {1 {expected 4 columns for 'v1err' but got 3}} ifcapable compound { do_test view-3.4 { execsql2 { CREATE VIEW v3 AS SELECT a FROM t1 UNION SELECT b FROM t1 ORDER BY b; SELECT * FROM v3 LIMIT 4; } |
︙ | ︙ | |||
459 460 461 462 463 464 465 466 467 468 469 470 471 472 | # Ticket #1270: Do not allow parameters in view definitions. # do_test view-12.1 { catchsql { CREATE VIEW v12 AS SELECT a FROM t1 WHERE b=? } } {1 {parameters are not allowed in views}} ifcapable attach { do_test view-13.1 { forcedelete test2.db catchsql { ATTACH 'test2.db' AS two; | > > > > > | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | # Ticket #1270: Do not allow parameters in view definitions. # do_test view-12.1 { catchsql { CREATE VIEW v12 AS SELECT a FROM t1 WHERE b=? } } {1 {parameters are not allowed in views}} do_test view-12.2 { catchsql { CREATE VIEW v12(x) AS SELECT a FROM t1 WHERE b=? } } {1 {parameters are not allowed in views}} ifcapable attach { do_test view-13.1 { forcedelete test2.db catchsql { ATTACH 'test2.db' AS two; |
︙ | ︙ |
Deleted tool/diffdb.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tool/mksqlite3c.tcl.
︙ | ︙ | |||
208 209 210 211 212 213 214 | # begin/end markers with the harmless substring "**". puts $out "/* [string map [list /* ** */ **] $line] */" } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {!$linemacros && [regexp {^#line} $line]} { # Skip #line directives. | | > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | # begin/end markers with the harmless substring "**". puts $out "/* [string map [list /* ** */ **] $line] */" } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {!$linemacros && [regexp {^#line} $line]} { # Skip #line directives. } elseif {$addstatic && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} { # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before # functions if this header file does not need it. if {![info exists varonly_hdr($tail)] && [regexp $declpattern $line all rettype funcname rest]} { regsub {^SQLITE_API } $line {} line # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. # so that linkage can be modified at compile-time. |
︙ | ︙ | |||
376 377 378 379 380 381 382 383 384 385 386 387 | rtree.c icu.c fts3_icu.c sqlrr.c sqlite3rbu.c dbstat.c } { copy_file tsrc/$file } close $out | > > | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | rtree.c icu.c fts3_icu.c sqlrr.c sqlite3rbu.c dbstat.c json1.c fts5.c } { copy_file tsrc/$file } close $out |
Changes to tool/mksqlite3h.tcl.
︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 80 | # Force the output to use unix line endings, even on Windows. fconfigure stdout -translation lf set filelist [subst { $TOP/src/sqlite.h.in $TOP/ext/rtree/sqlite3rtree.h }] # These are the functions that accept a variable number of arguments. They # always need to use the "cdecl" calling convention even when another calling # convention (e.g. "stcall") is being used for the rest of the library. set cdecllist { sqlite3_config | > | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | # Force the output to use unix line endings, even on Windows. fconfigure stdout -translation lf set filelist [subst { $TOP/src/sqlite.h.in $TOP/ext/rtree/sqlite3rtree.h $TOP/ext/fts5/fts5.h }] # These are the functions that accept a variable number of arguments. They # always need to use the "cdecl" calling convention even when another calling # convention (e.g. "stcall") is being used for the rest of the library. set cdecllist { sqlite3_config |
︙ | ︙ |
Deleted tool/opcodeDoc.awk.
|
| < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tool/space_used.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |